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.clickWithDebounce
|
||||||
import com.sw.dualscreen.ext.invisible
|
import com.sw.dualscreen.ext.invisible
|
||||||
import com.sw.dualscreen.ext.visible
|
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.FoodModule
|
||||||
import com.sw.dualscreen.objbox.ObjectBox
|
|
||||||
import com.sw.dualscreen.utils.FoodVectorTool
|
import com.sw.dualscreen.utils.FoodVectorTool
|
||||||
import com.sw.dualscreen.utils.L
|
import com.sw.dualscreen.utils.L
|
||||||
import com.sw.dualscreen.utils.NetworkUtils
|
import com.sw.dualscreen.utils.NetworkUtils
|
||||||
@@ -42,43 +39,11 @@ class InitActivity : BaseActivity<ActivityInitBinding>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getCollectedFoodVector(block: () -> Unit) {
|
private fun getCollectedFoodVector(block: () -> Unit) {
|
||||||
// userViewModel.getCollectedFoodVector(
|
FoodVectorTool.loadAndSaveFoodVector(
|
||||||
// param = mutableMapOf(
|
userViewModel = userViewModel,
|
||||||
// "pageNum" to "$pageNum",
|
lifecycleScope = lifecycleScope,
|
||||||
// "pageSize" to "$PAGE_SIZE",
|
successBlock = { block() },
|
||||||
// "version" to GlobalData.foodModelVersion
|
failureBlock = { getVectorErrorDialog() }
|
||||||
// )
|
|
||||||
// ) { 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()
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -215,19 +215,16 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
|||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
FaceServer.getInstance().clearAllFaces()
|
FaceServer.getInstance().clearAllFaces()
|
||||||
}
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
ObjectBox.removeAll()
|
ObjectBox.removeAll()
|
||||||
}
|
}
|
||||||
FoodVectorTool.getFoodVector(
|
FoodVectorTool.loadAndSaveFoodVector(
|
||||||
userViewModel = viewModel,
|
userViewModel = viewModel,
|
||||||
onPageFinish = { list ->
|
lifecycleScope = lifecycleScope,
|
||||||
list?.let { FoodVectorTool.saveFoodVector(lifecycleScope,list) }
|
|
||||||
},
|
|
||||||
successBlock = {
|
successBlock = {
|
||||||
viewModel.getUserFaceCache(pageNo = 1)
|
viewModel.getUserFaceCache(pageNo = 1)
|
||||||
}, failureBlock = {
|
},
|
||||||
hideWaitingDialog() // 显示提示信息
|
failureBlock = {
|
||||||
|
hideWaitingDialog()
|
||||||
ToastUtils.showToast(it)
|
ToastUtils.showToast(it)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -129,13 +129,15 @@ object SensorScaleUtils {
|
|||||||
/**
|
/**
|
||||||
* 零位标定
|
* 零位标定
|
||||||
*/
|
*/
|
||||||
fun zero() {
|
fun zero(isShowToastRemind: Boolean = false) {
|
||||||
Timber.d("zero isOpened = $isOpened, mSensorScale = $mSensorScale")
|
Timber.d("zero isOpened = $isOpened, mSensorScale = $mSensorScale")
|
||||||
if (!isOpened) return
|
if (!isOpened) return
|
||||||
mSensorScale?.zero {
|
mSensorScale?.zero {
|
||||||
isZero = true
|
isZero = true
|
||||||
Timber.d("zero 零位标定操作成功")
|
Timber.d("zero 零位标定操作成功")
|
||||||
ToastUtils.showToast("零位标定操作成功")
|
if (isShowToastRemind) {
|
||||||
|
ToastUtils.showToast("零位标定操作成功")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
package com.sw.dualscreen.utils
|
package com.sw.dualscreen.utils
|
||||||
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.LifecycleCoroutineScope
|
||||||
import com.sw.dualscreen.GlobalData
|
import com.sw.dualscreen.GlobalData
|
||||||
import com.sw.dualscreen.activity.InitActivity
|
|
||||||
import com.sw.dualscreen.model.response.FoodVector
|
import com.sw.dualscreen.model.response.FoodVector
|
||||||
import com.sw.dualscreen.objbox.Food
|
import com.sw.dualscreen.objbox.Food
|
||||||
import com.sw.dualscreen.objbox.ObjectBox
|
import com.sw.dualscreen.objbox.ObjectBox
|
||||||
@@ -10,15 +9,50 @@ import com.sw.dualscreen.viewmodel.UserViewModel
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
object FoodVectorTool {
|
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,
|
userViewModel: UserViewModel,
|
||||||
onPageFinish:(List<FoodVector>?)-> Unit,
|
lifecycleScope: LifecycleCoroutineScope,
|
||||||
successBlock: () -> Unit,
|
successBlock: () -> Unit,
|
||||||
failureBlock: (String) -> 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(
|
userViewModel.getCollectedFoodVector(
|
||||||
param = mutableMapOf(
|
param = mutableMapOf(
|
||||||
"pageNum" to "$pageNum",
|
"pageNum" to "$pageNum",
|
||||||
@@ -30,30 +64,36 @@ object FoodVectorTool {
|
|||||||
failureBlock("未查询到向量数据")
|
failureBlock("未查询到向量数据")
|
||||||
return@getCollectedFoodVector
|
return@getCollectedFoodVector
|
||||||
}
|
}
|
||||||
val list = items
|
// 第一页为空,视为成功(数据库无数据)
|
||||||
if (pageNum == 1 && list.isEmpty()) {
|
if (pageNum == 1 && items.isEmpty()) {
|
||||||
//接口成功无数据,暂时认为成功
|
|
||||||
successBlock()
|
successBlock()
|
||||||
return@getCollectedFoodVector
|
return@getCollectedFoodVector
|
||||||
}
|
}
|
||||||
if (list.size >= PAGE_SIZE) {
|
// 有数据则保存
|
||||||
onPageFinish(list)
|
if (items.isNotEmpty()) {
|
||||||
pageNum++
|
saveFoodVector(lifecycleScope, items)
|
||||||
getFoodVector(userViewModel, onPageFinish, successBlock, failureBlock)
|
|
||||||
return@getCollectedFoodVector
|
|
||||||
}
|
}
|
||||||
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 {
|
lifecycleScope.launch {
|
||||||
val vectorList = list.map { vt ->
|
val vectorList = list.map { vt ->
|
||||||
val foodVector = vt.foodVector?.removeSurrounding("[", "]")?.split(",")
|
// 解析向量字符串 "[0.1,0.2,...]" 为 FloatArray
|
||||||
?.map { it.toFloatOrNull() ?: 0.0f }?.toFloatArray()
|
val foodVector = vt.foodVector?.removeSurrounding("[", "]")
|
||||||
|
?.split(",")?.map { it.toFloatOrNull() ?: 0.0f }?.toFloatArray()
|
||||||
Food(
|
Food(
|
||||||
collectId = vt.id,
|
collectId = vt.id,
|
||||||
foodId = vt.foodId,
|
foodId = vt.foodId,
|
||||||
@@ -65,5 +105,4 @@ object FoodVectorTool {
|
|||||||
ObjectBox.putAll(vectorList)
|
ObjectBox.putAll(vectorList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user