From a45690d3be9599b07fd54238cc9b499aae3f6561 Mon Sep 17 00:00:00 2001 From: lvmeng <848755140@qq.com> Date: Tue, 7 Apr 2026 09:25:03 +0800 Subject: [PATCH] =?UTF-8?q?refactor(utils):=20=E9=87=8D=E6=9E=84=20FoodVec?= =?UTF-8?q?torTool=20=E5=B9=B6=E4=BC=98=E5=8C=96=20zero()=20=E6=8F=90?= =?UTF-8?q?=E7=A4=BA=E6=8E=A7=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 重构 FoodVectorTool:移除单例 pageNum 状态污染问题,分页逻辑下沉为私有 fetchPage,saveFoodVector 改为私有,PAGE_SIZE 移入内部定义,对外统一暴露 loadAndSaveFoodVector 接口 - 更新 InitActivity、MainActivity 调用方,移除重复的 onPageFinish 回调 - SensorScaleUtils.zero() 新增 isShowToastRemind 可选参数,支持按需显示标定成功提示 Co-Authored-By: Claude Sonnet 4.6 --- .../sw/dualscreen/activity/InitActivity.kt | 45 ++-------- .../sw/dualscreen/activity/MainActivity.kt | 13 ++- .../com/sw/dualscreen/sdk/SensorScaleUtils.kt | 6 +- .../com/sw/dualscreen/utils/FoodVectorTool.kt | 85 ++++++++++++++----- 4 files changed, 76 insertions(+), 73 deletions(-) diff --git a/app/src/main/java/com/sw/dualscreen/activity/InitActivity.kt b/app/src/main/java/com/sw/dualscreen/activity/InitActivity.kt index 8932efe..60e1838 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/InitActivity.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/InitActivity.kt @@ -13,10 +13,7 @@ import com.sw.dualscreen.dialog.RemindDialog import com.sw.dualscreen.ext.clickWithDebounce import com.sw.dualscreen.ext.invisible import com.sw.dualscreen.ext.visible -import com.sw.dualscreen.model.response.FoodVector -import com.sw.dualscreen.objbox.Food import com.sw.dualscreen.objbox.FoodModule -import com.sw.dualscreen.objbox.ObjectBox import com.sw.dualscreen.utils.FoodVectorTool import com.sw.dualscreen.utils.L import com.sw.dualscreen.utils.NetworkUtils @@ -42,43 +39,11 @@ class InitActivity : BaseActivity() { } private fun getCollectedFoodVector(block: () -> Unit) { -// userViewModel.getCollectedFoodVector( -// param = mutableMapOf( -// "pageNum" to "$pageNum", -// "pageSize" to "$PAGE_SIZE", -// "version" to GlobalData.foodModelVersion -// ) -// ) { items -> -// if (items == null) { -// getVectorErrorDialog() -// return@getCollectedFoodVector -// } -// val list = items -// if (pageNum == 1 && list.isEmpty()) { -// block() -// return@getCollectedFoodVector -// } -// if (list.size >= PAGE_SIZE) { -// saveFoodVector(list) -// pageNum++ -// getCollectedFoodVector(block) -// return@getCollectedFoodVector -// } -// if (list.isNotEmpty()) { -// saveFoodVector(list) -// block() -// } -// } - - FoodVectorTool.getFoodVector( - userViewModel, - onPageFinish = { list -> - list?.let { FoodVectorTool.saveFoodVector(lifecycleScope,list) } - }, successBlock = { - block() - }, failureBlock = { - getVectorErrorDialog() - } + FoodVectorTool.loadAndSaveFoodVector( + userViewModel = userViewModel, + lifecycleScope = lifecycleScope, + successBlock = { block() }, + failureBlock = { getVectorErrorDialog() } ) } diff --git a/app/src/main/java/com/sw/dualscreen/activity/MainActivity.kt b/app/src/main/java/com/sw/dualscreen/activity/MainActivity.kt index f2ee06d..41ae55f 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/MainActivity.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/MainActivity.kt @@ -215,19 +215,16 @@ class MainActivity : BaseActivity() { lifecycleScope.launch { withContext(Dispatchers.IO) { FaceServer.getInstance().clearAllFaces() - } - withContext(Dispatchers.IO) { ObjectBox.removeAll() } - FoodVectorTool.getFoodVector( + FoodVectorTool.loadAndSaveFoodVector( userViewModel = viewModel, - onPageFinish = { list -> - list?.let { FoodVectorTool.saveFoodVector(lifecycleScope,list) } - }, + lifecycleScope = lifecycleScope, successBlock = { viewModel.getUserFaceCache(pageNo = 1) - }, failureBlock = { - hideWaitingDialog() // 显示提示信息 + }, + failureBlock = { + hideWaitingDialog() ToastUtils.showToast(it) } ) diff --git a/app/src/main/java/com/sw/dualscreen/sdk/SensorScaleUtils.kt b/app/src/main/java/com/sw/dualscreen/sdk/SensorScaleUtils.kt index 7d2d65a..e96d935 100644 --- a/app/src/main/java/com/sw/dualscreen/sdk/SensorScaleUtils.kt +++ b/app/src/main/java/com/sw/dualscreen/sdk/SensorScaleUtils.kt @@ -129,13 +129,15 @@ object SensorScaleUtils { /** * 零位标定 */ - fun zero() { + fun zero(isShowToastRemind: Boolean = false) { Timber.d("zero isOpened = $isOpened, mSensorScale = $mSensorScale") if (!isOpened) return mSensorScale?.zero { isZero = true Timber.d("zero 零位标定操作成功") - ToastUtils.showToast("零位标定操作成功") + if (isShowToastRemind) { + ToastUtils.showToast("零位标定操作成功") + } } } diff --git a/app/src/main/java/com/sw/dualscreen/utils/FoodVectorTool.kt b/app/src/main/java/com/sw/dualscreen/utils/FoodVectorTool.kt index d191f00..2d16b71 100644 --- a/app/src/main/java/com/sw/dualscreen/utils/FoodVectorTool.kt +++ b/app/src/main/java/com/sw/dualscreen/utils/FoodVectorTool.kt @@ -1,8 +1,7 @@ package com.sw.dualscreen.utils -import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.LifecycleCoroutineScope import com.sw.dualscreen.GlobalData -import com.sw.dualscreen.activity.InitActivity import com.sw.dualscreen.model.response.FoodVector import com.sw.dualscreen.objbox.Food import com.sw.dualscreen.objbox.ObjectBox @@ -10,15 +9,50 @@ import com.sw.dualscreen.viewmodel.UserViewModel import kotlinx.coroutines.launch object FoodVectorTool { - var pageNum: Int = 1 - const val PAGE_SIZE: Int = InitActivity.PAGE_SIZE - fun getFoodVector( + /** 每页拉取条数 */ + private const val PAGE_SIZE = 100 + + /** + * 统一入口:分页拉取所有食物向量数据并保存到本地 ObjectBox + * + * @param userViewModel 请求 ViewModel + * @param lifecycleScope 协程作用域(用于保存操作) + * @param successBlock 全部数据拉取并保存成功后回调 + * @param failureBlock 任意一次请求失败时回调,参数为错误信息 + */ + fun loadAndSaveFoodVector( userViewModel: UserViewModel, - onPageFinish:(List?)-> Unit, + lifecycleScope: LifecycleCoroutineScope, successBlock: () -> Unit, failureBlock: (String) -> Unit - ): Unit { + ) { + // 每次调用从第 1 页开始,避免单例状态污染 + fetchPage( + pageNum = 1, + userViewModel = userViewModel, + lifecycleScope = lifecycleScope, + successBlock = successBlock, + failureBlock = failureBlock + ) + } + + /** + * 递归分页请求(内部方法,外部不感知分页细节) + * + * @param pageNum 当前页码 + * @param userViewModel 请求 ViewModel + * @param lifecycleScope 协程作用域 + * @param successBlock 成功回调 + * @param failureBlock 失败回调 + */ + private fun fetchPage( + pageNum: Int, + userViewModel: UserViewModel, + lifecycleScope: LifecycleCoroutineScope, + successBlock: () -> Unit, + failureBlock: (String) -> Unit + ) { userViewModel.getCollectedFoodVector( param = mutableMapOf( "pageNum" to "$pageNum", @@ -30,30 +64,36 @@ object FoodVectorTool { failureBlock("未查询到向量数据") return@getCollectedFoodVector } - val list = items - if (pageNum == 1 && list.isEmpty()) { - //接口成功无数据,暂时认为成功 + // 第一页为空,视为成功(数据库无数据) + if (pageNum == 1 && items.isEmpty()) { successBlock() return@getCollectedFoodVector } - if (list.size >= PAGE_SIZE) { - onPageFinish(list) - pageNum++ - getFoodVector(userViewModel, onPageFinish, successBlock, failureBlock) - return@getCollectedFoodVector + // 有数据则保存 + if (items.isNotEmpty()) { + saveFoodVector(lifecycleScope, items) } - if (list.isNotEmpty()) { - onPageFinish(list) + // 数据量达到一页上限,继续拉取下一页 + if (items.size >= PAGE_SIZE) { + fetchPage(pageNum + 1, userViewModel, lifecycleScope, successBlock, failureBlock) + } else { + successBlock() } - successBlock() } } - fun saveFoodVector(lifecycleScope: androidx.lifecycle.LifecycleCoroutineScope ,list: List) { + /** + * 将向量数据列表保存到 ObjectBox 本地数据库 + * + * @param lifecycleScope 协程作用域 + * @param list 待保存的食物向量数据列表 + */ + private fun saveFoodVector(lifecycleScope: LifecycleCoroutineScope, list: List) { lifecycleScope.launch { val vectorList = list.map { vt -> - val foodVector = vt.foodVector?.removeSurrounding("[", "]")?.split(",") - ?.map { it.toFloatOrNull() ?: 0.0f }?.toFloatArray() + // 解析向量字符串 "[0.1,0.2,...]" 为 FloatArray + val foodVector = vt.foodVector?.removeSurrounding("[", "]") + ?.split(",")?.map { it.toFloatOrNull() ?: 0.0f }?.toFloatArray() Food( collectId = vt.id, foodId = vt.foodId, @@ -65,5 +105,4 @@ object FoodVectorTool { ObjectBox.putAll(vectorList) } } - -} \ No newline at end of file +}