refactor(utils): 重构 FoodVectorTool 并优化 zero() 提示控制
- 重构 FoodVectorTool:移除单例 pageNum 状态污染问题,分页逻辑下沉为私有 fetchPage,saveFoodVector 改为私有,PAGE_SIZE 移入内部定义,对外统一暴露 loadAndSaveFoodVector 接口 - 更新 InitActivity、MainActivity 调用方,移除重复的 onPageFinish 回调 - SensorScaleUtils.zero() 新增 isShowToastRemind 可选参数,支持按需显示标定成功提示 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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<ActivityInitBinding>() {
|
||||
}
|
||||
|
||||
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() }
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -215,19 +215,16 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
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)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -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("零位标定操作成功")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<FoodVector>?)-> 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<FoodVector>) {
|
||||
/**
|
||||
* 将向量数据列表保存到 ObjectBox 本地数据库
|
||||
*
|
||||
* @param lifecycleScope 协程作用域
|
||||
* @param list 待保存的食物向量数据列表
|
||||
*/
|
||||
private fun saveFoodVector(lifecycleScope: LifecycleCoroutineScope, list: List<FoodVector>) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user