fix(scale): 优化秤数据同步及格口显示顺序
- 增加秤号到列表索引的映射,提升心跳回调数据定位效率 - 调整重量数据处理逻辑,减少索引查找开销 - 按设备物理布局重排格口列表,解决多列设备显示错乱问题 - 定义同步间隔和首次同步延迟常量,统一定时任务配置 - 调整重量上报心跳间隔为1秒,提升秤数据实时性 - 清空列表时同步清理秤号映射,防止脏数据影响展示 - 优化空格口清理逻辑,改用映射位置快速更新对应项
This commit is contained in:
@@ -76,8 +76,8 @@ object ScaleManager {
|
||||
/** 当前设备激活码,非空时收到激活请求自动应答 */
|
||||
private var activateCode: String = ""
|
||||
|
||||
/** 心跳应答:心跳上报间隔(秒),默认5秒 */
|
||||
var heartbeatInterval: Int = 5
|
||||
/** 心跳应答:心跳上报间隔(秒),默认1秒,保证重量更新实时性 */
|
||||
var heartbeatInterval: Int = 1
|
||||
|
||||
/** 心跳应答:开锁后未开门自动落锁时间(秒),默认6秒 */
|
||||
var lockTimeout: Int = 6
|
||||
|
||||
@@ -46,12 +46,20 @@ import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
class HomeV3Activity : BaseActivity() {
|
||||
|
||||
companion object {}
|
||||
companion object {
|
||||
/** 重量同步后台间隔(秒) */
|
||||
private const val SYNC_INTERVAL_SECONDS = 30L
|
||||
/** 首次同步延迟(秒) */
|
||||
private const val SYNC_INITIAL_DELAY_SECONDS = 10L
|
||||
}
|
||||
|
||||
override val enableRightStatusMenu: Boolean = true
|
||||
|
||||
private val list: MutableList<SlotModel> = mutableListOf()
|
||||
|
||||
/** 秤号(slotNo 数字部分)→ list 索引 的快速查找表,心跳回调中 O(1) 定位 */
|
||||
private val scaleIndexToPosition = mutableMapOf<Int, Int>()
|
||||
|
||||
private var shelfIndex = 0
|
||||
|
||||
private fun isNeedOpenLock() = App.deviceId == "4787e213-90ab-3e32-88e0-ac271a937751"
|
||||
@@ -72,15 +80,12 @@ class HomeV3Activity : BaseActivity() {
|
||||
.init(activateCode = ProtocolConstants.ACTIVE_MAP[App.deviceId] ?: "")
|
||||
.onHeartbeat { _, data ->
|
||||
data.weights.forEach { weight ->
|
||||
val shelfNo = weight.index
|
||||
val pos = list.indexOfFirst {
|
||||
it.slotNo.filter { c -> c.isDigit() }.toIntOrNull() == shelfNo
|
||||
}
|
||||
val model = list.getOrNull(pos) ?: return@forEach
|
||||
val pos = scaleIndexToPosition[weight.index] ?: return@forEach
|
||||
val model = list[pos]
|
||||
model.weight = weight.grams / 1000.0
|
||||
shelfAdapter.notifyItemChanged(pos)
|
||||
log("getWeightInfo: slotNo=${model.slotNo}, realWeight=${weight.grams}, temp=${data.temperature}")
|
||||
EventBus.getDefault().post(SendWeightEvent(shelfNo, weight.grams))
|
||||
EventBus.getDefault().post(SendWeightEvent(weight.index, weight.grams))
|
||||
}
|
||||
}
|
||||
.onTempReport { frame ->
|
||||
@@ -158,7 +163,8 @@ class HomeV3Activity : BaseActivity() {
|
||||
log("updateUI: slots=${slots.size}, rows=$rows, columns=$columns")
|
||||
|
||||
list.clear()
|
||||
list.addAll(slots)
|
||||
list.addAll(reorderSlotsByDeviceLayout(slots, columns, rows))
|
||||
buildScaleIndexMap()
|
||||
|
||||
val displayMetrics = resources.displayMetrics
|
||||
// 减去 RecyclerView + item 自身的 margin
|
||||
@@ -172,6 +178,64 @@ class HomeV3Activity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按设备物理布局重排格口列表。
|
||||
*
|
||||
* API 返回的 slots 按 slotNo 升序排列。FlexboxLayoutManager(FlexDirection.COLUMN)
|
||||
* 按列填充(先填满第一列 5 行,再换第二列),3 列设备需要重排才能正确显示:
|
||||
*
|
||||
* 期望显示: 列填充需要的列表序:
|
||||
* [1] [6] [7] [1, 2, 3, 4, 5, ← 第1列
|
||||
* [2] [8] [9] 6, 8, 10, 12, 14, ← 第2列
|
||||
* [3][10] [11] 7, 9, 11, 13, 15] ← 第3列
|
||||
* [4][12] [13]
|
||||
* [5][14] [15]
|
||||
*
|
||||
* 2 列设备 API 原序 [1..10] 列填充后恰好正确,无需重排。
|
||||
*
|
||||
* @param slots API 返回的格口列表(按 slotNo 升序)
|
||||
* @param columns 列数(API horizontalRows)
|
||||
* @param rows 行数(API verticalCount)
|
||||
*/
|
||||
private fun reorderSlotsByDeviceLayout(
|
||||
slots: List<SlotModel>,
|
||||
columns: Int,
|
||||
rows: Int
|
||||
): List<SlotModel> {
|
||||
// 2 列及以下无需重排,API 原序列填充后恰好正确
|
||||
if (columns <= 2) return ArrayList(slots)
|
||||
|
||||
// 按 slotNo 数字部分建立查找表
|
||||
val slotMap = HashMap<Int, SlotModel>(slots.size)
|
||||
for (slot in slots) {
|
||||
val num = slot.slotNo.filter { it.isDigit() }.toIntOrNull() ?: continue
|
||||
slotMap[num] = slot
|
||||
}
|
||||
|
||||
val result = ArrayList<SlotModel>(slots.size)
|
||||
for (displayCol in 0 until columns) {
|
||||
for (displayRow in 0 until rows) {
|
||||
// 物理布局 → FlexDirection.COLUMN 列填充所需的列表位置
|
||||
val slotNo = when (displayCol) {
|
||||
0 -> displayRow + 1 // 左列: 1,2,3,4,5
|
||||
1 -> rows + 1 + displayRow * 2 // 中列: 6,8,10,12,14
|
||||
else -> rows + 2 + displayRow * 2 // 右列: 7,9,11,13,15
|
||||
}
|
||||
slotMap[slotNo]?.let { result.add(it) }
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/** 预建秤号→列表索引映射表,供心跳回调 O(1) 查找 */
|
||||
private fun buildScaleIndexMap() {
|
||||
scaleIndexToPosition.clear()
|
||||
list.forEachIndexed { pos, model ->
|
||||
val scaleNo = model.slotNo.filter { it.isDigit() }.toIntOrNull() ?: return@forEachIndexed
|
||||
scaleIndexToPosition[scaleNo] = pos
|
||||
}
|
||||
}
|
||||
|
||||
private fun showError(message: String) {
|
||||
Loading.dismiss()
|
||||
toast(message)
|
||||
@@ -302,6 +366,7 @@ class HomeV3Activity : BaseActivity() {
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun loadEmptyView() {
|
||||
list.clear()
|
||||
scaleIndexToPosition.clear()
|
||||
shelfAdapter.notifyDataSetChanged()
|
||||
binding.include?.let {
|
||||
it.root.visible()
|
||||
@@ -319,10 +384,7 @@ class HomeV3Activity : BaseActivity() {
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun clearEmptyShelf(event: ClearShelfEvent) {
|
||||
val index = list.indexOfFirst {
|
||||
it.slotNo?.filter { c -> c.isDigit() }?.toIntOrNull() == event.shelfNo
|
||||
}
|
||||
if (index < 0) return
|
||||
val index = scaleIndexToPosition[event.shelfNo] ?: return
|
||||
list[index] = list[index].copy(materName = "")
|
||||
shelfAdapter.notifyItemChanged(index)
|
||||
}
|
||||
@@ -332,7 +394,10 @@ class HomeV3Activity : BaseActivity() {
|
||||
|
||||
private fun saveGoodsTask() {
|
||||
saveTaskJob =
|
||||
taskExecutor.startIntervalTaskWithInitialDelay(10 * 1000L, 1 * 60 * 1000L) {
|
||||
taskExecutor.startIntervalTaskWithInitialDelay(
|
||||
SYNC_INITIAL_DELAY_SECONDS * 1000L,
|
||||
SYNC_INTERVAL_SECONDS * 1000L
|
||||
) {
|
||||
syncShelfGoodsToServer()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user