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