refactor(main): 将Thread替换为lifecycleScope并优化协程处理

- 替换CollectFragment中的Thread为activity.lifecycleScope.launch
- 在MainActivity中添加FaceServer相关依赖和协程调度器
- 修改环境切换对话框以支持人脸数据重置功能
- 将照片拍摄和食物向量保存操作从Thread迁移到lifecycleScope
- 优化人脸识别数据更新逻辑,移除不必要的线程创建
- 修改onTakePhotoSuccess方法为suspend函数并调整UI更新方式
- 更新主线程操作使用withContext(Dispatchers.Main)替代runOnUiThread
- 在MainScreenPresentation中添加相机暂停功能
- 修复SensorScaleUtils中标定调用问题
- 扩展UserViewModel的人脸数据获取接口,支持回调处理
This commit is contained in:
2026-04-02 17:35:37 +08:00
parent 12da153df3
commit 5479091959
5 changed files with 111 additions and 78 deletions
@@ -68,10 +68,14 @@ import com.sw.plate.utils.LightManager
import com.sw.plate.utils.ToastUtils import com.sw.plate.utils.ToastUtils
import com.sw.plate.utils.arcface.facedb.FaceDatabase import com.sw.plate.utils.arcface.facedb.FaceDatabase
import com.sw.plate.utils.arcface.facedb.entity.FaceEntity import com.sw.plate.utils.arcface.facedb.entity.FaceEntity
import com.sw.plate.utils.arcface.faceserver.FaceServer
import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import okhttp3.RequestBody import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.Subscribe
@@ -205,7 +209,16 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
} }
updateDateTime() updateDateTime()
binding.tvTitleTime.setOnClickListener { binding.tvTitleTime.setOnClickListener {
EnvSwitchDialog(this).show() EnvSwitchDialog(context = this, onEnvChanged = {
showWaitingDialog("重置人脸数据中……")
FaceServer.getInstance().clearAllFaces()
viewModel.getUserFaceCache(pageNo = 1, onSuccess = {
hideWaitingDialog()
ToastUtils.showToast("人脸数据已更新")
}, onFailure = { errMsg ->
ToastUtils.showToast(errMsg)
})
}).show()
} }
binding.ivSetting.setOnClickListener { binding.ivSetting.setOnClickListener {
isRefreshPage = false isRefreshPage = false
@@ -410,12 +423,19 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
LightManager.closeRedLight() LightManager.closeRedLight()
LightManager.openGreenLight() LightManager.openGreenLight()
showWaitingDialog("识别中,请稍后……") showWaitingDialog("识别中,请稍后……")
lifecycleScope.launch {
delay(5000)
withContext(Dispatchers.Main) {
hideWaitingDialog()
}
}
takePhoto(successCallback = { photoUri -> takePhoto(successCallback = { photoUri ->
Thread { lifecycleScope.launch {
onTakePhotoSuccess(photoUri) onTakePhotoSuccess(photoUri)
}.start() }
failCount = 0 failCount = 0
}, failureCallback = { }, failureCallback = {
log("registerDataChange main,拍照异常,请重试")
//ToastUtils.showToast("拍照异常,请重试") //ToastUtils.showToast("拍照异常,请重试")
failCount++ failCount++
hideWaitingDialog() hideWaitingDialog()
@@ -809,9 +829,9 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
if (checkedItem?.isFromSearch == true) { if (checkedItem?.isFromSearch == true) {
//当前菜名为手动搜索选择,非识别结果,保存向量数据 //当前菜名为手动搜索选择,非识别结果,保存向量数据
Thread { lifecycleScope.launch {
saveFoodVector(checkedItem!!) saveFoodVector(checkedItem!!)
}.start() }
} }
}, 300) }, 300)
} }
@@ -1074,14 +1094,15 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
if (list.isEmpty()) { if (list.isEmpty()) {
return@runOnUiThread return@runOnUiThread
} }
lifecycleScope.launch {
updateFaceData(list) updateFaceData(list)
} }
}
}) })
} }
} }
private fun updateFaceData(list: List<UserFaceModel>) { private fun updateFaceData(list: List<UserFaceModel>) {
Thread {
val faceList = mutableListOf<FaceEntity>() val faceList = mutableListOf<FaceEntity>()
try { try {
list.forEach { model -> list.forEach { model ->
@@ -1111,7 +1132,6 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }
}.start()
} }
private fun sendFaceData(faceData: String) { private fun sendFaceData(faceData: String) {
@@ -1125,18 +1145,16 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
private var tcpClient: TcpClient? = null private var tcpClient: TcpClient? = null
private fun onTakePhotoSuccess(photoUri: Uri) { private suspend fun onTakePhotoSuccess(photoUri: Uri) {
lastPhotoUri = photoUri lastPhotoUri = photoUri
log("registerDataChange main,takePhoto耗时:${System.currentTimeMillis() - startTime}") log("registerDataChange main,takePhoto耗时:${System.currentTimeMillis() - startTime}")
startTime = System.currentTimeMillis() startTime = System.currentTimeMillis()
log("registerDataChange photoUri = ${photoUri.path}") log("registerDataChange photoUri = ${photoUri.path}")
// viewModel.getIdentifiedFoodList() // viewModel.getIdentifiedFoodList()
lifecycleScope.launch {
ImageUtil.uriToBitmap(this@MainActivity, photoUri)?.let { bitmap -> ImageUtil.uriToBitmap(this@MainActivity, photoUri)?.let { bitmap ->
queryFoodData(bitmap) queryFoodData(bitmap)
} }
} }
}
private suspend fun queryFoodData(bitmap: Bitmap) { private suspend fun queryFoodData(bitmap: Bitmap) {
log("registerDataChange main,uriToBitmap耗时:${System.currentTimeMillis() - startTime}") log("registerDataChange main,uriToBitmap耗时:${System.currentTimeMillis() - startTime}")
@@ -1163,7 +1181,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
hideWaitingDialog() hideWaitingDialog()
log("registerDataChange photoUri 识别数据名称:$foodName") log("registerDataChange photoUri 识别数据名称:$foodName")
runOnUiThread { withContext(Dispatchers.Main) {
binding.flPay.run { binding.flPay.run {
//0-计费,1-不计费 //0-计费,1-不计费
val chargeMode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0) val chargeMode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0)
@@ -1176,7 +1194,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
LightManager.closeRedLight() LightManager.closeRedLight()
//binding.layoutRescan.visibility = View.VISIBLE //binding.layoutRescan.visibility = View.VISIBLE
runOnUiThread { withContext(Dispatchers.Main) {
binding.tvToSearch.let { binding.tvToSearch.let {
it.text = "未识别到,手动搜索" it.text = "未识别到,手动搜索"
it.visible() it.visible()
@@ -118,11 +118,11 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
collectionAdapter.notifyItemChanged(index) collectionAdapter.notifyItemChanged(index)
} }
// settingActivity?.hideWaitingDialog() // settingActivity?.hideWaitingDialog()
Thread { activity?.lifecycleScope?.launch {
ImageUtil.uriToBitmap(requireActivity(), uri)?.let { bitmap -> ImageUtil.uriToBitmap(requireActivity(), uri)?.let { bitmap ->
getImageVector(index, bitmap) getImageVector(index, bitmap)
} }
}.start() }
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
settingActivity?.hideWaitingDialog() settingActivity?.hideWaitingDialog()
@@ -1041,6 +1041,7 @@ class MainScreenPresentation(
return@runOnUiThread return@runOnUiThread
} }
} }
pauseCamera()
step3ShowRecognizeResult(userId) step3ShowRecognizeResult(userId)
}) })
@@ -1313,6 +1314,7 @@ class MainScreenPresentation(
mealPickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0) ?: 0 mealPickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0) ?: 0
Timber.tag(TAG).i("$lastFaceTrackId 用户离开") Timber.tag(TAG).i("$lastFaceTrackId 用户离开")
lastFaceTrackId = -1 lastFaceTrackId = -1
//resumeCamera()
Timber.tag(TAG) Timber.tag(TAG)
.d("postUserData userNutritionData是否null ${userNutrition == null}, currentFood是否null: ${currentFood == null}currentUserId是否null${currentUserId == null}") .d("postUserData userNutritionData是否null ${userNutrition == null}, currentFood是否null: ${currentFood == null}currentUserId是否null${currentUserId == null}")
if (userNutrition == null || currentFood == null || currentUserId == null) { if (userNutrition == null || currentFood == null || currentUserId == null) {
@@ -87,8 +87,7 @@ object SensorScaleUtils {
// Thread.sleep(1000) // Thread.sleep(1000)
// TODO: 暂时不标定--------- // TODO: 暂时不标定---------
//zero() zero()
}.start() }.start()
} }
} }
@@ -91,21 +91,36 @@ class UserViewModel : BaseViewModel() {
/** /**
* 获取人脸数据 * 获取人脸数据
*/ */
fun getUserFaceCache(pageNo: Int = 1, pageSize: Int = PAGE_SIZE) { fun getUserFaceCache(
pageNo: Int = 1,
pageSize: Int = PAGE_SIZE,
onSuccess: () -> Unit = {},
onFailure: (String) -> Unit = {}
) {
// Initialize current page number
var currentPageNo = pageNo var currentPageNo = pageNo
// Debug log to track current page
Timber.tag(TAG).d("getUserFaceCache index = $currentPageNo") Timber.tag(TAG).d("getUserFaceCache index = $currentPageNo")
// Launch a coroutine to perform the face data retrieval
launch { launch {
// Set loading state to false
_loadFaceResult.value = false _loadFaceResult.value = false
//获取全量数据时,时间戳改为0 //获取全量数据时,时间戳改为0
SpTool.lastFaceTimestamp = 0 SpTool.lastFaceTimestamp = 0
val response = repository.getUserFaceCache(currentPageNo) val response = repository.getUserFaceCache(currentPageNo)
if (parseResponse(response)) { val check = parseResponse(response)
if (!check) {
// 获取失败
onFailure("获取人脸数据失败,${response.msg}(${response.code})")
return@launch
}
// 获取成功一次后缓存状态 // 获取成功一次后缓存状态
SPUtil.getInstance().put(GlobalKey.KEY_FIRST_RUN, true) SPUtil.getInstance().put(GlobalKey.KEY_FIRST_RUN, true)
withContext(Dispatchers.Default) { withContext(Dispatchers.Default) {
val list: List<UserFaceModel> = response.data ?: emptyList() val list: List<UserFaceModel> = response.data ?: emptyList()
if (pageNo == 1 && list.isEmpty()) { if (pageNo == 1 && list.isEmpty()) {
//ToastUtils.showToast("查询人脸数据为空") //ToastUtils.showToast("查询人脸数据为空")
onFailure("查询人脸数据为空")
return@withContext return@withContext
} }
//val item = list.map { it.member } //val item = list.map { it.member }
@@ -130,8 +145,8 @@ class UserViewModel : BaseViewModel() {
} }
SpTool.lastFaceTimestamp = lastFaceTimestamp SpTool.lastFaceTimestamp = lastFaceTimestamp
_loadFaceResult.value = true _loadFaceResult.value = true
onSuccess()
} }
// val nextPageIndex = response.result?.nextPageIndex ?: -1 // val nextPageIndex = response.result?.nextPageIndex ?: -1
// if (nextPageIndex > 0) { // if (nextPageIndex > 0) {
// getUserFaceCache(nextPageIndex) // getUserFaceCache(nextPageIndex)
@@ -140,7 +155,6 @@ class UserViewModel : BaseViewModel() {
// } // }
} }
} }
}
// fun getUserFaceCache2(index: Int = 0) { // fun getUserFaceCache2(index: Int = 0) {
// Timber.d("getUserFaceCache index = $index") // Timber.d("getUserFaceCache index = $index")