@@ -3,11 +3,11 @@ package com.shuwei.intelligent.shelves.activity
import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.util.SparseIntArray
import androidx.activity.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
@@ -26,7 +26,6 @@ import com.shuwei.intelligent.shelves.model.ShelfBody
import com.shuwei.intelligent.shelves.model.ShelfModel
import com.shuwei.intelligent.shelves.model.ShelfResult
import com.shuwei.intelligent.shelves.model.WeightEvent
import com.shuwei.intelligent.shelves.net.HomeViewModel
import com.shuwei.intelligent.shelves.net.Loading
import com.shuwei.intelligent.shelves.net.NetViewModel
import com.shuwei.intelligent.shelves.net.RespData
@@ -43,7 +42,6 @@ import com.shuwei.intelligent.shelves.utils.ext.toast
import com.shuwei.intelligent.shelves.utils.ext.visible
import com.shuwei.intelligent.shelves.utils.hexToBinary
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
@@ -99,6 +97,16 @@ class HomeActivity : BaseActivity() {
const val TEMPERATURE _CTRL = " ${HEADER} 0F01040000 ${FOOTER} "
val list : MutableList < ShelfModel > = mutableListOf ( )
val weightArray = SparseIntArray ( )
var shelfIndex = 0
// public fun getRealWeight():Double = weightArray[shelfIndex]?:0.0
// 温度
var showTemperatureC = " 0 "
// 湿度
var showHumidity = " 0 "
}
//401-false, 1楼餐厅-true
@@ -107,7 +115,6 @@ class HomeActivity : BaseActivity() {
private lateinit var binding : ActivityHomeBinding
private val viewModel : NetViewModel by viewModels ( )
private val homeViewModel : HomeViewModel by viewModels ( )
@SuppressLint ( " NotifyDataSetChanged " , " HardwareIds " )
override fun onCreate ( savedInstanceState : Bundle ? ) {
@@ -121,23 +128,13 @@ class HomeActivity : BaseActivity() {
updateLeftStatus ( " " )
initRecyclerView ( )
// 串口初始化:独立协程,仅执行一次
lifecycleScope . launch {
val openState = SerialPortManager . open ( )
log ( " onCreate: openState= $openState " )
if ( openState ) {
// 串口回调在 IO 线程,通过 Channel 无锁传递数据,不再嵌套 launch
SerialPortManager . startReceive { data ->
serialDataChannel . trySend ( data )
}
//SerialPortManager.send(DEVICE_INFO_CMD)
}
}
// 串口数据消费:单一协程串行处理,serialReader 访问不存在并发竞争
// 更新UI显示接收数据
lifecycleScope . launch {
for ( data in serialDataChannel ) {
try {
receiveSerialPortData ( data )
} catch ( e : Exception ) {
@@ -145,10 +142,9 @@ class HomeActivity : BaseActivity() {
}
}
}
// ViewModel 状态观察:STARTED 状态下收集,onStop 时自动取消,onStart 时恢复
lifecycleScope . launch {
repeatOnLifecycle ( Lifecycle . State . STARTED ) {
//SerialPortManager.send(DEVICE_INFO_CMD)
}
repeatOnLifecycle ( Lifecycle . State . CREATED ) {
launch {
viewModel . getAccessTokenUiState . collect { state ->
when ( state ) {
@@ -206,16 +202,16 @@ class HomeActivity : BaseActivity() {
}
private fun loadTestData ( ) {
homeViewModel . shelfItems . add ( ShelfModel ( deviceNo = 1 , goodsName = " 鸡蛋 " , deviceId = App . deviceId ) )
homeViewModel . shelfItems . add ( ShelfModel ( deviceNo = 6 , goodsName = " " , deviceId = App . deviceId ) )
homeViewModel . shelfItems . add ( ShelfModel ( deviceNo = 2 , goodsName = " " , deviceId = App . deviceId ) )
homeViewModel . shelfItems . add ( ShelfModel ( deviceNo = 7 , goodsName = " 生姜 " , deviceId = App . deviceId ) )
homeViewModel . shelfItems . add ( ShelfModel ( deviceNo = 3 , goodsName = " 黄瓜 " , deviceId = App . deviceId ) )
homeViewModel . shelfItems . add ( ShelfModel ( deviceNo = 8 , goodsName = " " , deviceId = App . deviceId ) )
homeViewModel . shelfItems . add ( ShelfModel ( deviceNo = 4 , goodsName = " 梨 " , deviceId = App . deviceId ) )
homeViewModel . shelfItems . add ( ShelfModel ( deviceNo = 9 , goodsName = " 梨 " , deviceId = App . deviceId ) )
homeViewModel . shelfItems . add ( ShelfModel ( deviceNo = 5 , goodsName = " " , deviceId = App . deviceId ) )
homeViewModel . shelfItems . add ( ShelfModel ( deviceNo = 10 , goodsName = " " , deviceId = App . deviceId ) )
list . add ( ShelfModel ( deviceNo = 1 , goodsName = " 鸡蛋 " , deviceId = App . deviceId ) )
list . add ( ShelfModel ( deviceNo = 6 , goodsName = " " , deviceId = App . deviceId ) )
list . add ( ShelfModel ( deviceNo = 2 , goodsName = " " , deviceId = App . deviceId ) )
list . add ( ShelfModel ( deviceNo = 7 , goodsName = " 生姜 " , deviceId = App . deviceId ) )
list . add ( ShelfModel ( deviceNo = 3 , goodsName = " 黄瓜 " , deviceId = App . deviceId ) )
list . add ( ShelfModel ( deviceNo = 8 , goodsName = " " , deviceId = App . deviceId ) )
list . add ( ShelfModel ( deviceNo = 4 , goodsName = " 梨 " , deviceId = App . deviceId ) )
list . add ( ShelfModel ( deviceNo = 9 , goodsName = " 梨 " , deviceId = App . deviceId ) )
list . add ( ShelfModel ( deviceNo = 5 , goodsName = " " , deviceId = App . deviceId ) )
list . add ( ShelfModel ( deviceNo = 10 , goodsName = " " , deviceId = App . deviceId ) )
shelfAdapter . notifyDataSetChanged ( )
}
@@ -255,12 +251,12 @@ class HomeActivity : BaseActivity() {
// toast("数据错误")
// return
// }
homeViewModel . shelfItems . clear ( )
list . clear ( )
val subList01 = tempList . subList ( 0 , tempList . size / 2 )
val subList02 = tempList . subList ( tempList . size / 2 , tempList . size )
repeat ( tempList . size / 2 ) { index ->
homeViewModel . shelfItems . add ( subList01 [ index ] . also { it . deviceId = App . deviceId } )
homeViewModel . shelfItems . add ( subList02 [ index ] . also { it . deviceId = App . deviceId } )
list . add ( subList01 [ index ] . also { it . deviceId = App . deviceId } )
list . add ( subList02 [ index ] . also { it . deviceId = App . deviceId } )
}
shelfAdapter . notifyDataSetChanged ( )
}
@@ -281,18 +277,7 @@ class HomeActivity : BaseActivity() {
*/
private var terminalVersion : String = " "
/**
* 串口数据接收通道,无界缓冲。
* IO 线程(串口回调)通过 trySend 写入,单一消费协程串行读取,
* 确保 serialReader 始终在同一协程中访问,规避并发竞争。
*/
private val serialDataChannel = Channel < String > ( Channel . UNLIMITED )
/**
* 串口数据拼包缓冲器。
* 仅由 serialDataChannel 的单一消费协程访问,线程安全。
*/
private val serialReader = StringBuilder ( )
private val serialReader by lazy { StringBuilder ( ) }
private fun receiveSerialPortData ( srcData : String ) {
log ( " receiveSerialPortData: $srcData " )
@@ -429,7 +414,7 @@ class HomeActivity : BaseActivity() {
//D6DADEDB1001015D020000000027001E00020000001E001C00B40000000000010000000100040000001900440003000F00000000000FFFE6000200010002FFD80044000300010005001E0001FFD80056001400280000000000000000008300090000003C00D2000000000000007F003700000000A100000031323136334238423134303233303456322E313100FFFF
runOnUiThread {
if ( tipDialog == null ) {
tipDialog = CommonDialog ( this ) . apply {
CommonDialog ( this ) . apply {
dialogTitle = " 温馨提示 "
// dialogContent = logMsg
confirmBlock = {
@@ -528,21 +513,21 @@ class HomeActivity : BaseActivity() {
var realWeight = 0
var firstByteBinary = hexToBinary ( weightHex . substring ( 0 , 2 ) )
if ( firstByteBinary . startsWith ( " 0 " ) ) {
//正数:按十六进制解析,失败时兜底为 0
realWeight = weightHex . toIntOrNull ( 16 ) ?: 0
//正数
realWeight = weightHex . toInt ( )
} else {
//负数:清除符号位后取绝对值,再取反
//负数
firstByteBinary = " 0 ${firstByteBinary.substring(1)} "
val firstByteHex = binaryToHex ( firstByteBinary )
weightHex = firstByteHex + weightHex . substring ( 2 )
realWeight = - 1 * ( weightHex . toIntOrNull ( 16 ) ?: 0 )
realWeight = - 1 * weightHex . toInt ( )
}
homeViewModel . putWeight ( index , realWeight )
weightArray . put ( index , realWeight )
if ( index in 1 .. 10 && homeViewModel . shelfItems . size == 10 ) {
homeViewModel . shelfItems . firstOrNull { it . deviceNo == index } ?. let {
if ( index in 1 .. 10 && list . size == 10 ) {
list . firstOrNull { it . deviceNo == index } ?. let {
it . weight = realWeight . toDouble ( )
val pos = homeViewModel . shelfItems . indexOf ( it )
val pos = list . indexOf ( it )
shelfAdapter . notifyItemChanged ( pos )
log ( " getWeightInfo: deviceNo= ${it.deviceNo} ,realWeight= ${realWeight} " )
EventBus . getDefault ( ) . post ( SendWeightEvent ( it . deviceNo , realWeight ) )
@@ -623,44 +608,35 @@ class HomeActivity : BaseActivity() {
// TaskManager.cancelTask()
saveTaskJob ?. cancel ( )
overdueTaskJob ?. cancel ( )
// 关闭 Channel,消费协程的 for 循环将随之结束
serialDataChannel . close ( )
// 销毁前关闭 Dialog,防止 Activity 已销毁时窗口仍附着导致泄漏
tipDialog ?. dismiss ( )
tipDialog = null
EventBus . getDefault ( ) . unregister ( this )
super . onDestroy ( )
}
@Suppress ( " DEPRECATION " )
private val shelfAdapter by lazy {
ShelfAdapter ( homeViewModel . shelfItems ) . apply {
ShelfAdapter ( list ) . apply {
setOnItemClickListener { _ , _ , position ->
homeViewModel . selectedShelfIndex = position
shelfIndex = position
lifecycleScope . launch {
if ( isNeedOpenLock ) {
val openCmd = if ( homeViewModel . shelfItems [ position ] . deviceNo in 1 .. 5 )
val openCmd = if ( list [ position ] . deviceNo in 1 .. 5 )
LEFT _SHELF _OPEN _CMD
else
RIGHT _SHELF _OPEN _CMD
val openState = SerialPortManager . send ( openCmd )
}
// if (openState.not()) {
// toast("${homeViewModel.shelfItems [position].goodsName}柜门开启失败")
// toast("${list [position].goodsName}柜门开启失败")
// return@launch
// }
//SerialPortManager.send(START_CMD)
launch ( Intent ( this @HomeActivity , ShelfActivity :: class . java ) . also {
it . putExtra ( ShelfActivity . SHELF _MODEL , homeViewModel . shelfItems [ position ] )
it . putExtra ( ShelfActivity . SHELF _MODEL , list [ position ] )
} ) {
it ?. run {
// API 33 起支持带类型参数的重载,低版本回退旧 API + as? 安全转换
val model = if ( Build . VERSION . SDK _INT >= Build . VERSION_CODES . TIRAMISU ) {
getSerializableExtra ( ShelfActivity . SHELF _MODEL , ShelfModel :: class . java )
} else {
@Suppress ( " DEPRECATION " )
getSerializableExtra ( ShelfActivity . SHELF _MODEL ) as ? ShelfModel
} ?: return @run
homeViewModel . shelfItems [ position ] . apply {
val model =
getSerializableExtra ( ShelfActivity . SHELF _MODEL ) as ShelfModel
list [ position ] . apply {
goodsId = model . goodsId
goodsName = model . goodsName
weight = model . weight
@@ -672,12 +648,12 @@ class HomeActivity : BaseActivity() {
try {
val submitList = homeViewModel . shelfItems . sortedBy { item -> item . deviceNo }
val submitList = list . sortedBy { item -> item . deviceNo }
val body = ShelfBody ( ) . also { body ->
body . deviceId = App . deviceId ?: " "
body . canteenId = App . canteenId
body . temperature = homeViewModel . temperatureC
body . humidity = homeViewModel . humidity
body . temperature = showTemperatureC
body . humidity = showHumidity
body . goodsList = submitList
}
Log . d ( " mzf " , " performSync: body: ${body.toJsonString()} " )
@@ -738,7 +714,7 @@ class HomeActivity : BaseActivity() {
@SuppressLint ( " NotifyDataSetChanged " )
private fun loadEmptyView ( ) {
homeViewModel . shelfItems . clear ( )
list . clear ( )
shelfAdapter . notifyDataSetChanged ( )
binding . include ?. let {
@@ -759,7 +735,7 @@ class HomeActivity : BaseActivity() {
@Subscribe ( threadMode = ThreadMode . MAIN )
public fun clearEmptyShelf ( event : ClearShelfEvent ) {
val item = homeViewModel . shelfItems . firstOrNull { it . deviceNo == event . shelfNo }
val item = list . firstOrNull { it . deviceNo == event . shelfNo }
item ?. apply {
goodsId = " "
goodsName = null
@@ -768,7 +744,7 @@ class HomeActivity : BaseActivity() {
createTime = null
overdueDay = null
}
shelfAdapter . notifyItemChanged ( homeViewModel . shelfItems . indexOf ( item ) )
shelfAdapter . notifyItemChanged ( list . indexOf ( item ) )
}
private val taskExecutor by lazy { IntervalExecutor ( ) }
@@ -797,14 +773,10 @@ class HomeActivity : BaseActivity() {
private fun updateOverdueState ( ) {
viewModel . updateOverdueState { state , items ->
if ( items . isNullOrEmpty ( ) ) return @updateOverdueState
homeViewModel . shelfItems . forEachIndexed { index , model ->
// 按 deviceNo 精确匹配接口数据,避免:
// 1. 两端列表大小不一致时的 IndexOutOfBoundsException
// 2. 本地列表交叉排列与接口顺序不一致导致的状态串位
val serverModel = items . find { it . deviceNo == model . deviceNo }
?: return @forEachIndexed
if ( serverModel . overdue != model . overdue ) {
model . overdue = serverModel . overdue
list . forEachIndexed { index , model ->
//接口过期状态变化后更新状态
if ( items [ index ] . overdue != model . overdue ) {
model . overdue = items [ index ] . overdue
shelfAdapter . notifyItemChanged ( index )
log ( " 更新编号为 ${model.deviceNo} 物品: ${model.goodsName} 的过期状态: ${model.overdue} " )
}
@@ -813,18 +785,22 @@ class HomeActivity : BaseActivity() {
}
private fun saveShelfGoodsList ( ) {
log ( " performSync: list: ${homeViewModel.shelfItems .toJsonString()} " )
val submitList = homeViewModel . shelfItems . sortedBy { it . deviceNo }
log ( " performSync: list: ${list .toJsonString()} " )
val submitList = list . sortedBy { it . deviceNo }
submitList . forEach {
if ( it . goodsId . isNullOrBlank ( ) ) {
it . weight = it . weightBak
}
}
// submitList.forEach {
// it.temperature = HomeActivity.showTemperatureC
// it.humidity = HomeActivity.showHumidity
// }
val body = ShelfBody ( ) . also {
it . deviceId = App . deviceId
it . canteenId = App . canteenId
it . temperature = homeViewModel . temperatureC
it . humidity = homeViewModel . humidity
it . temperature = showTemperatureC
it . humidity = showHumidity
it . goodsList = submitList
}
log ( " performSync: body: ${body.toJsonString()} " )