13、人脸识别与Activity生命周期:onResume启动认证、onPause取消认证、屏幕旋转处理
说实话,人脸识别认证跟Activity生命周期打交道这件事,很多新手容易翻车。我刚开始做的时候也觉得——不就是启动认证、取消认证嘛,有什么难的?结果第一次上线就被用户投诉:手机转个方向,人脸认证就卡死了。嗯,从那以后我再也不敢小看这个环节了。
今天咱们就聊聊,怎么把BiometricPrompt和Activity的生命周期玩明白。
为什么要在onResume启动认证?
你想想看,用户打开App,人脸认证弹出来,这时候如果Activity还没准备好——比如界面还在重建、数据还没恢复——那认证弹窗可能就显示异常,甚至直接崩溃。
onResume是Activity可见且可交互的信号。 我个人习惯把认证启动放在这里,因为这时候界面已经准备好了,用户也能看到弹窗。
核心原则: 认证启动必须保证Activity处于前台且可见状态。
@Override
protected void onResume() {
super.onResume();
// 我习惯在这里启动人脸认证
if (shouldShowBiometricPrompt) {
startBiometricAuth();
}
}
这里有个细节——shouldShowBiometricPrompt这个标志位。为什么要加它?因为onResume可能会被多次调用,比如从别的Activity返回、屏幕旋转等。不加这个标志位,每次onResume都会弹认证,用户体验就很糟糕。
onPause取消认证,这个坑我踩过
onPause对应的是Activity即将失去焦点。说白了,用户可能按了Home键、接了个电话、或者跳转到其他页面。这时候如果人脸认证还在进行,会有什么问题?
- 认证回调可能还在执行,但Activity已经不可见了
- 弹窗可能显示在错误的界面上
- 严重情况下会导致内存泄漏或崩溃
所以,在onPause中取消认证是必须的。
@Override
protected void onPause() {
super.onPause();
// 我曾经忘记加这个,结果用户按Home键后认证弹窗还在
cancelBiometricAuth();
}
private void cancelBiometricAuth() {
if (biometricPrompt != null) {
biometricPrompt.cancelAuthentication();
}
}
注意: cancelAuthentication()调用后,BiometricPrompt会立即停止认证,并且不会再回调onAuthenticationError。所以如果你在onPause中取消了认证,后续的onResume中需要重新启动。
屏幕旋转处理——最容易被忽视的坑
屏幕旋转会导致Activity重建。这个过程会触发:
onPause → onStop → onDestroy → onCreate → onStart → onResume
如果处理不当,会出现什么情况?
- 旋转前认证弹窗正在显示
- Activity销毁重建
- 旧的BiometricPrompt实例失效
- 新的Activity没有重新启动认证
- 用户看到空白界面,认证卡死
我遇到过这个问题,当时用户反馈说「手机横过来就认证不了了」。排查了半天,发现就是屏幕旋转导致认证状态丢失。
解决方案: 在onSaveInstanceState中保存认证状态,在onRestoreInstanceState中恢复。
private static final String KEY_AUTH_IN_PROGRESS = "auth_in_progress";
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(KEY_AUTH_IN_PROGRESS, isAuthInProgress);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (savedInstanceState != null) {
isAuthInProgress = savedInstanceState.getBoolean(KEY_AUTH_IN_PROGRESS);
}
}
@Override
protected void onResume() {
super.onResume();
if (isAuthInProgress) {
startBiometricAuth();
}
}
小技巧: 如果你不想让Activity在屏幕旋转时重建,可以在AndroidManifest中配置android:configChanges="orientation|screenSize"。但我不建议这么做,因为这样会失去系统对配置变化的自动处理能力。
完整的生命周期处理流程
下面这张图是我自己总结的,把整个流程串起来看会更清楚:
避坑指南
我总结了几条实战中容易踩的坑,你写代码的时候可以留意一下:
| 场景 | 问题 | 解决方案 |
|---|---|---|
| 快速切换App | onPause取消认证后,onResume又启动,导致频繁弹窗 | 加一个延迟标志位,比如500ms内不重复启动 |
| 多窗口模式 | Activity进入多窗口,onPause被调用,认证取消 | 判断isInMultiWindowMode(),特殊处理 |
| Fragment嵌套 | Fragment的onResume/onPause与Activity不同步 | 在Fragment中单独管理认证生命周期 |
| 认证回调延迟 | onPause中取消认证,但回调仍在执行 | 使用弱引用持有Activity,避免内存泄漏 |
特别提醒: 不要在onCreate或onStart中启动认证。这时候Activity还没完全可见,弹窗可能会显示异常。我见过有人这么写,结果在部分机型上弹窗位置错乱。
嗯,关于生命周期和人脸认证的配合,核心就这些。说白了就是三个字——对得上。启动和取消要对得上Activity的前后台状态,旋转前后的状态要对得上。做到这几点,基本就不会出大问题。
公众号:蓝海资料掘金营,微信deep3321