refactor(activity): 全面优化 LoginByFaceActivity 代码质量

- 移除静态 instance 引用,消除潜在内存泄漏风险
- Observer {} 显式包装统一改为 Kotlin lambda 写法
- 匿名 Debouncer 改为成员变量 openDebouncer(修复防抖失效 bug)
- Thread.start() 替换为 lifecycleScope.launch(Dispatchers.IO)
- Arrays.fill() 替换为 Kotlin ByteArray.fill(),移除 Java import
- 清理死字段:regDebouncer、faceUseSwitch、faceFailThreshold、tempUserId
- Java getter 语法统一改为 Kotlin 属性访问
- 移除 protected override、无效 handleLoginSuccess override 等冗余代码
- 顶部添加 @file:Suppress("DEPRECATION") 统一处理废弃 API 警告

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-03 10:18:39 +08:00
co-authored by Claude Sonnet 4.6
parent 08f1963054
commit dca9496bee
@@ -1,3 +1,5 @@
@file:Suppress("DEPRECATION")
package com.sw.platecabinet.activity
import android.Manifest
@@ -10,10 +12,8 @@ import android.util.DisplayMetrics
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.widget.ImageView
import androidx.annotation.RequiresApi
import androidx.core.view.isVisible
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import com.arcsoft.face.ErrorInfo
import com.bumptech.glide.Glide
@@ -58,12 +58,13 @@ import com.sw.platecabinet.utils.PlateUtils
import com.sw.platecabinet.utils.RegisterCallbackHandler
import com.sw.platecabinet.utils.SoundPoolUtil
import com.sw.platecabinet.utils.SpTool
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import timber.log.Timber
import java.io.File
import java.util.Arrays
import java.util.concurrent.atomic.AtomicBoolean
/**
@@ -89,22 +90,13 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
companion object {
private const val TAG = "LoginByFaceActivity"
private var instance: LoginByFaceActivity? = null
private const val COLLECT_SUCCESS = "collect_success"
private const val RECOGNIZE_SUCCESS = "recognize_success"
private const val NO_PLATE_REMIND = "no_plate_remind";
fun goInitActivity() {
instance?.goInitActivity()
}
private const val NO_PLATE_REMIND = "no_plate_remind"
}
// private var logList: MutableList<String> = mutableListOf()
// private val logAdapter by lazy { LogAdapter(logList) }
override fun initialize() {
instance = this
userViewModel.activeEngine()
initArcViewModel()
@@ -174,7 +166,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
private var rgbFaceRectTransformer: FaceRectTransformer? = null
private val livenessType = LivenessType.RGB
private var openRectInfoDraw = false
private val regDebouncer = Debouncer(3000)
private val leftDebouncer = Debouncer(30*1000)
private var registerHandler: RegisterCallbackHandler? = null
@@ -213,7 +205,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
}
}
}
recognizeViewModel.ftInitCode.observe(this, Observer { ftInitCode: Int? ->
recognizeViewModel.ftInitCode.observe(this) { ftInitCode: Int? ->
if (ftInitCode != ErrorInfo.MOK) {
val error: String? = getString(
R.string.specific_engine_init_failed, "ftEngine",
@@ -222,8 +214,8 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
Timber.e("ftInitCode observe = $error")
ToastUtils.showToast(error)
}
})
recognizeViewModel.frInitCode.observe(this, Observer { frInitCode: Int? ->
}
recognizeViewModel.frInitCode.observe(this) { frInitCode: Int? ->
if (frInitCode != ErrorInfo.MOK) {
val error: String? = getString(
R.string.specific_engine_init_failed, "frEngine",
@@ -232,8 +224,8 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
Timber.e("frInitCode observe = $error")
ToastUtils.showToast(error)
}
})
recognizeViewModel.flInitCode.observe(this, Observer { flInitCode: Int? ->
}
recognizeViewModel.flInitCode.observe(this) { flInitCode: Int? ->
if (flInitCode != ErrorInfo.MOK) {
val error: String? = getString(
R.string.specific_engine_init_failed, "flEngine",
@@ -242,31 +234,26 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
Timber.e("flInitCode observe = $error")
ToastUtils.showToast(error)
}
})
}
recognizeViewModel.recognizeConfiguration
.observe(this, Observer { recognizeConfiguration: RecognizeConfiguration? ->
.observe(this) { recognizeConfiguration: RecognizeConfiguration? ->
Timber.i("recognizeConfiguration: observe = ${recognizeConfiguration.toString()}")
})
recognizeViewModel.recognizeNotice.observe(this, Observer { notice: String? ->
}
recognizeViewModel.recognizeNotice.observe(this) { notice: String? ->
Timber.i("recognizeNotice observe notice = $notice")
})
}
recognizeViewModel.recognizeUserId.observe(this, Observer { result: CompareResult? ->
recognizeViewModel.recognizeUserId.observe(this) { result: CompareResult? ->
loadLogInfo("collectFace,recognizeUserId observe userId = ${result?.faceEntity?.userName}")
loadFaceRecognizeResult3(result)
})
}
recognizeViewModel.drawRectInfoText.observe(this, Observer { info ->
recognizeViewModel.drawRectInfoText.observe(this) { info ->
Timber.i("drawRectInfoText observe info = $info")
})
}
}
/**
* 人脸识别开关,true-loadFaceRecognizeResult2false-loadFaceRecognizeResult
*/
private var faceUseSwitch = true
/**
* 识别失败重试次数
*/
@@ -277,11 +264,6 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
*/
private val maxFailCount = 5
/**
* 人脸失败阈值
*/
private val faceFailThreshold = 0.3
/**
* 配置阈值,默认值为0.8
*/
@@ -295,8 +277,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
binding.tvSimilarValue.text = "$similar${retryFailCount}"
loadLogInfo(
"collectFace,recognizeUserId 阈值 success=$faceSuccessThreshold, " +
"fail=$faceFailThreshold, similar=$similar, retry=$retryFailCount"
"collectFace,recognizeUserId 阈值 success=$faceSuccessThreshold, similar=$similar, retry=$retryFailCount"
)
if (similar >= faceSuccessThreshold) {
val userId = result.faceEntity?.userName
@@ -309,7 +290,6 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
return
}
// if (similar <= faceFailThreshold || retryFailCount >= maxFailCount) {
if (retryFailCount >= maxFailCount) {
loadLogInfo(
"collectFace,recognizeUserId 识别失败,开始采集 similar=$similar, " +
@@ -404,7 +384,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
item.updateTime = DateTimeUtils.getDateTimeString()
item.plateNumber = null
plateEnable = false
Debouncer(5000).debounce {
openDebouncer.debounce {
//打开柜子
PlateUtils.open(this, item.equipmentBoxCode, false) {
goInitActivity()
@@ -416,20 +396,19 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
SpTool.savePlateData(items)
}
}
// private val debouncer by lazy { Debouncer(3000) }
private val openDebouncer by lazy { Debouncer(5000) }
private fun initArcView() {
//在布局结束后才做初始化操作
binding.dualCameraTexturePreviewRgb.getViewTreeObserver().addOnGlobalLayoutListener(this)
recognizeViewModel.getCompareResultList().getValue()
binding.dualCameraTexturePreviewRgb.viewTreeObserver.addOnGlobalLayoutListener(this)
val list = recognizeViewModel.getCompareResultList().getValue()
loadLogInfo("initArcView:list.size=${list?.size}")
}
override fun onDestroy() {
loadLogInfo("onDestroy")
instance = null
if (rgbCameraHelper != null) {
rgbCameraHelper!!.release()
rgbCameraHelper?.release()
rgbCameraHelper = null
}
@@ -474,7 +453,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
layoutParams.width = (measuredHeight * ratio).toInt()
}
if (scale < 1f) {
val rgbParam = rgbPreview.getLayoutParams()
val rgbParam = rgbPreview.layoutParams
layoutParams.width = (rgbParam.width * scale).toInt()
layoutParams.height = (rgbParam.height * scale).toInt()
} else {
@@ -510,8 +489,8 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
isMirror: Boolean
) {
loadLogInfo("initRgbCamera Rgb onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation")
runOnUiThread({
val previewSizeRgb = camera.getParameters().getPreviewSize()
runOnUiThread {
val previewSizeRgb = camera.parameters.previewSize
val layoutParams = adjustPreviewViewSize(
binding.dualCameraTexturePreviewRgb,
binding.dualCameraTexturePreviewRgb, binding.dualCameraFaceRectView,
@@ -545,7 +524,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
recognizeViewModel.onRgbCameraOpened(camera)
recognizeViewModel.setRgbFaceRectTransformer(rgbFaceRectTransformer)
})
}
}
@RequiresApi(api = Build.VERSION_CODES.Q)
@@ -607,8 +586,8 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
.previewOn(binding.dualCameraTexturePreviewRgb)
.cameraListener(cameraListener)
.build()
rgbCameraHelper!!.init()
rgbCameraHelper!!.start()
rgbCameraHelper?.init()
rgbCameraHelper?.start()
}
/**
@@ -634,7 +613,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
override fun onGlobalLayout() {
loadLogInfo("onGlobalLayout")
binding.dualCameraTexturePreviewRgb.getViewTreeObserver().removeOnGlobalLayoutListener(this)
binding.dualCameraTexturePreviewRgb.viewTreeObserver.removeOnGlobalLayoutListener(this)
// 请求权限
checkCameraPermission()
}
@@ -644,7 +623,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
if (rgbCameraHelper != null && rgbCameraHelper!!.isStopped) {
loadLogInfo("collectFace,resumeCamera: ")
isRecognition = true
rgbCameraHelper!!.start()
rgbCameraHelper?.start()
} else {
//recognizeViewModel.onPreviewFrame(ByteArray(1382400), true)
@@ -669,9 +648,11 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
// Y 分量(亮度)设为 0(全黑),UV 分量设为 128(默认值)
// 1. 填充 Y 分量(前 frameSize 个字节)
Arrays.fill(nv21Data, 0, frameSize, 0.toByte())
// Arrays.fill(nv21Data, 0, frameSize, 0.toByte())
nv21Data.fill(0, 0, frameSize)
// 2. 填充 UV 分量(后 frameSize/2 个字节)
Arrays.fill(nv21Data, frameSize, nv21Data.size, 128.toByte())
// Arrays.fill(nv21Data, frameSize, nv21Data.size, 128.toByte())
nv21Data.fill(128.toByte(), frameSize, nv21Data.size)
return nv21Data
}
@@ -680,10 +661,10 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
val emptyFrame = createBlackNV21Frame(1920, 1080)
// 传递“空帧” recognizeViewModel.onPreviewFrame(emptyFrame, true)
/**
* 临时用户id
*/
private var tempUserId: String = ""
// /**
// * 临时用户id
// */
// private var tempUserId: String = ""
override fun onResume() {
super.onResume()
try {
@@ -714,7 +695,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
isCollectFace = false
plateEnable = true
collectCount = 0
tempUserId = "${System.currentTimeMillis()}"
// tempUserId = "${System.currentTimeMillis()}"
resumeCamera()
registerHandler = RegisterCallbackHandler()
@@ -741,7 +722,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
private var isFirstOpen = true
protected override fun onPause() {
override fun onPause() {
pauseCamera()
super.onPause()
CountDownManager.cancelCountDown()
@@ -752,11 +733,6 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
// recognizeViewModel.onPreviewFrame(emptyFrame, true)
}
override fun handleLoginSuccess(equipmentUserInfo: EquipmentUserInfo, isAdmin: Boolean) {
super.handleLoginSuccess(equipmentUserInfo, isAdmin)
// goInitActivity()
}
private fun judgeRecognizeState(): Boolean {
val rectColor = binding.dualCameraFaceRectView.rectColor
if (rectColor == RecognizeColor.COLOR_SUCCESS && currentUserId.isNullOrBlank().not() && facePreviewInfoList.isNullOrEmpty().not()) {
@@ -823,7 +799,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
loadLogInfo("collectFace,sendFaceData: ----------12,发送人脸数据成功但接口返回为null,faceData=${faceData}")
return@addUserFace
}
Thread {
lifecycleScope.launch(Dispatchers.IO) {
saveFaceInfo(faceModel) {
runOnUiThread {
Glide.with(this@LoginByFaceActivity).load(imageFile).into(binding.ivCollectPhoto)
@@ -866,7 +842,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
private var currentUserId: String? = null
private fun saveFaceInfo(faceModel: UserFaceModel, block:()-> Unit= {}) {
private fun saveFaceInfo(faceModel: UserFaceModel, block: () -> Unit = {}) {
try {
loadLogInfo("collectFace,saveFaceInfo: ----------8,保存人脸取特征数据-----------")
val faceDao = FaceDatabase.getInstance(this).faceDao()