refactor(login): 优化出盘流程并增强错误处理
- 抽取出盘成功与失败的统一处理方法,简化代码逻辑 - 新增新用户注册采集成功后立即出盘功能,避免与识别成功逻辑冲突 - 出盘成功后取消识别倒计时并控制出盘开关,防止重复出盘 - 出盘失败时统一提示错误并跳转回初始页 - 采集成功后立即异步出盘,确保上传失败时仍能出盘 - 调整识别失败计数重置逻辑,避免无人脸短暂丢帧导致计数异常 - 在人脸离开时重置识别失败计数,保证下次重新累计 - 网络请求增加异常捕获,防止因异常导致回调阻塞无反馈
This commit is contained in:
@@ -417,29 +417,68 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
|
||||
PlcHelper.getInstance(this@LoginByFaceActivity)
|
||||
.outPlate(object : PlcCallback<String> {
|
||||
override fun onSuccess(result: String) {
|
||||
plateEnable = false
|
||||
recognizeCountDownUtil.cancelCountDown()
|
||||
// result 为 false 时表示出盘后无餐盘,直接播放无盘提示音
|
||||
if (result.equals("false", ignoreCase = true)) {
|
||||
loadLogInfo("collectFace,openPlate: result=false,餐盘已空")
|
||||
SoundPoolUtil.getInstance().play(NO_PLATE_REMIND, 0)
|
||||
goInitActivity()
|
||||
return
|
||||
}
|
||||
loadLogInfo("collectFace,openPlate: 出盘完成,result=$result,开始查询剩余餐盘")
|
||||
// result 为 true,出盘成功,再查询是否还有剩余餐盘
|
||||
SoundPoolUtil.getInstance().play(RECOGNIZE_SUCCESS, 0)
|
||||
checkRemainingPlate()
|
||||
onOutPlateSuccess(result, RECOGNIZE_SUCCESS)
|
||||
}
|
||||
|
||||
override fun onError(message: String) {
|
||||
ToastUtils.showToast("出盘失败,message=$message")
|
||||
loadLogInfo("collectFace,openPlate: 出盘失败,message=$message")
|
||||
goInitActivity()
|
||||
onOutPlateError(message)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 新用户注册采集成功后立即出盘(与上传后台并行,互不阻塞)。
|
||||
* 故意不经过 recognizeSuccess:避免使用临时 userId、避免与识别成功的防抖语义混淆。
|
||||
*/
|
||||
private fun outPlateForRegister() {
|
||||
loadLogInfo("collectFace,outPlateForRegister: 新用户采集成功,立即出盘,plateEnable=$plateEnable")
|
||||
if (plateEnable.not()) return
|
||||
|
||||
PlcHelper.getInstance(this@LoginByFaceActivity)
|
||||
.outPlate(object : PlcCallback<String> {
|
||||
override fun onSuccess(result: String) {
|
||||
loadLogInfo("collectFace,outPlateForRegister: 出盘完成,result=$result")
|
||||
onOutPlateSuccess(result, COLLECT_SUCCESS)
|
||||
}
|
||||
|
||||
override fun onError(message: String) {
|
||||
onOutPlateError(message)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 出盘成功后的统一处理:
|
||||
* 1. 置 plateEnable=false、取消识别倒计时,防止重复出盘;
|
||||
* 2. result 为 "false" 表示出盘后已无餐盘,播放无盘提示音并跳转;
|
||||
* 3. 否则播放提示音并查询剩余餐盘状态。
|
||||
*
|
||||
* @param result PLC 返回结果("false" 表示出盘后无餐盘)
|
||||
* @param successSound 出盘成功播放的提示音 key(识别成功 / 采集成功)
|
||||
*/
|
||||
private fun onOutPlateSuccess(result: String, successSound: String) {
|
||||
plateEnable = false
|
||||
recognizeCountDownUtil.cancelCountDown()
|
||||
if (result.equals("false", ignoreCase = true)) {
|
||||
loadLogInfo("collectFace,onOutPlateSuccess: result=false,餐盘已空")
|
||||
SoundPoolUtil.getInstance().play(NO_PLATE_REMIND, 0)
|
||||
goInitActivity()
|
||||
return
|
||||
}
|
||||
SoundPoolUtil.getInstance().play(successSound, 0)
|
||||
checkRemainingPlate()
|
||||
}
|
||||
|
||||
/**
|
||||
* 出盘失败后的统一处理:提示失败并跳转回初始页
|
||||
*/
|
||||
private fun onOutPlateError(message: String) {
|
||||
ToastUtils.showToast("出盘失败,message=$message")
|
||||
loadLogInfo("collectFace,onOutPlateError: 出盘失败,message=$message")
|
||||
goInitActivity()
|
||||
}
|
||||
|
||||
/**
|
||||
* 出盘成功后查询剩余餐盘状态,无盘则播放提示音
|
||||
*/
|
||||
@@ -617,7 +656,9 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
|
||||
userFaceInfo = null
|
||||
binding.btnCollect.tag = ""
|
||||
binding.tvSimilarValue.text = ""
|
||||
retryFailCount = 0
|
||||
// 注意:此处不再重置 retryFailCount。
|
||||
// 人脸检测会抖动(短暂丢帧),若每次无人脸就清零,"尝试几次失败"将无法累计。
|
||||
// 失败计数仅在识别成功、会话重启、确认用户离开时清零。
|
||||
// 人脸离开时,发送空帧清除 ViewModel 内部识别缓存,防止再次进入时使用旧数据
|
||||
recognizeViewModel.onPreviewFrame(emptyFrame, true)
|
||||
if (binding.llCollectButton.isVisible) {
|
||||
@@ -922,6 +963,9 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
|
||||
//block(faceData, headBmp)
|
||||
isCollecting.set(false)
|
||||
isCollectFace = false
|
||||
// 采集成功后立即出盘,与上传后台并行执行,确保上传失败时仍能吐盘
|
||||
outPlateForRegister()
|
||||
// 异步上传后台(上传成功后才入库),不阻塞出盘
|
||||
sendFaceData(faceData, headBmp)
|
||||
}
|
||||
|
||||
@@ -950,9 +994,8 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
|
||||
recognizeViewModel.refreshFaceList()
|
||||
loadLogInfo("collectFace,saveFaceInfo: ----------11,刷新人脸数据-----------")
|
||||
runOnUiThread {
|
||||
//采集完成,不再识别,直接提示成功
|
||||
//采集完成,停止识别(出盘已在采集成功时由 outPlateForRegister 触发,此处仅负责入库)
|
||||
isRecognition = false
|
||||
recognizeSuccess("${System.currentTimeMillis()}")
|
||||
}
|
||||
loadLogInfo("---------------------------------")
|
||||
collectCount = 0
|
||||
@@ -984,6 +1027,8 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
|
||||
loadLogInfo("leftCountDown.onFinish-人脸未离开,不跳转")
|
||||
return@startCountDown
|
||||
}
|
||||
// 确认用户已离开画面,重置识别失败计数,下次进入重新累计
|
||||
retryFailCount = 0
|
||||
goInitActivity()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -249,18 +249,24 @@ class NetViewModelV2 : ViewModel() {
|
||||
*/
|
||||
fun addUserFace(faceData: String, imageFile: File, block: (Boolean, UserFaceModelV2?) -> Unit) {
|
||||
viewModelScope.launch {
|
||||
val imageResp = repository.uploadImage(imageFile)
|
||||
val imageUrl = imageResp.data ?: ""
|
||||
if (imageUrl.isBlank()) {
|
||||
try {
|
||||
val imageResp = repository.uploadImage(imageFile)
|
||||
val imageUrl = imageResp.data ?: ""
|
||||
if (imageUrl.isBlank()) {
|
||||
block(false, null)
|
||||
return@launch
|
||||
}
|
||||
val faceResp = repository.addUserFace(faceData, imageUrl)
|
||||
if (faceResp.isSuccess().not()) {
|
||||
block(false, null)
|
||||
return@launch
|
||||
}
|
||||
block(true, faceResp.data)
|
||||
} catch (e: Exception) {
|
||||
// 网络或解析异常时同样回调失败,避免 block 永不触发导致上层无反馈
|
||||
e.printStackTrace()
|
||||
block(false, null)
|
||||
return@launch
|
||||
}
|
||||
val faceResp = repository.addUserFace(faceData, imageUrl)
|
||||
if (faceResp.isSuccess().not()) {
|
||||
block(false, null)
|
||||
return@launch
|
||||
}
|
||||
block(true, faceResp.data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user