4. ProcessLifecycleOwner 场景应用:全局应用前后台切换时相机释放与恢复
4.1 原理
Activity 或 Fragment 的 LifecycleOwner 只能感知自身组件的生命周期,无法覆盖应用全局的前后台切换(如用户按下 Home 键后再返回)。ProcessLifecycleOwner 是 Android Lifecycle 库提供的全局生命周期观测者,它代表整个应用进程的生命周期,可监听 ON_START(应用进入前台)和 ON_STOP(应用进入后台)。利用这一能力,开发者能在应用切到后台时立即释放 CameraX 相机资源(避免后台占用摄像头导致系统杀进程或其他应用无法使用),并在切回前台时安全恢复相机。
4.2 实现流程
- 在 app 模块
build.gradle添加lifecycle-process依赖。 - 在 Application 类或任意组件中获取 ProcessLifecycleOwner 实例。
- 注册
LifecycleObserver监听ON_START和ON_STOP事件。 - 在
ON_STOP中调用ProcessCameraProvider.getInstance(context).get()获取 CameraProvider 并关闭所有用例。 - 在
ON_START中重新绑定预览/分析等用例(参考标准 CameraX 启动流程)。 - 使用
AtomicBoolean或状态标记避免重复绑定/释放。
4.3 典型代码实现
// build.gradle (app) 依赖
implementation "androidx.lifecycle:lifecycle-process:2.6.2"
implementation "androidx.camera:camera-lifecycle:1.3.4"
// Application 或主 Activity 中注册全局观察者
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(new AppLifecycleObserver());
}
}
class AppLifecycleObserver implements LifecycleObserver {
private static final String TAG = "AppLifecycle";
private AtomicBoolean isResuming = new AtomicBoolean(false);
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void onAppBackground() {
Log.d(TAG, "应用进入后台 → 释放相机");
releaseCamera();
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
void onAppForeground() {
if (isResuming.compareAndSet(false, true)) {
Log.d(TAG, "应用回到前台 → 恢复相机");
bindCameraUseCases();
}
}
private void releaseCamera() {
// 通过单例或全局持有 CameraProvider 和用例
CameraXManager.getInstance().releaseAll();
}
private void bindCameraUseCases() {
CameraXManager.getInstance().bind(
// 传入当前前台 Activity 的 LifecycleOwner
getCurrentActivityLifecycleOwner(),
// 预览用例, 分析用例...
);
isResuming.set(false);
}
}
4.4 API 与配置说明
| API / 注解 | 作用 |
|---|---|
ProcessLifecycleOwner.get().getLifecycle() | 获取全局进程 Lifecycle 对象 |
@OnLifecycleEvent(Lifecycle.Event.ON_STOP) | 标记方法在应用进入后台时执行 |
@OnLifecycleEvent(Lifecycle.Event.ON_START) | 标记方法在应用回到前台时执行 |
ProcessCameraProvider.getInstance(context) | 获取 CameraX 的异步提供者 |
ListenableFuture.addListener(...) | 用于在 CameraProvider 就绪后执行绑定 |
4.5 调试与验证技巧
- 在
onAppBackground和onAppForeground中添加详细日志,使用adb logcat -s AppLifecycle CameraX过滤。 - 手动模拟前后台:按下 Home 键 → 观察日志是否触发释放;点击最近任务返回 → 观察是否触发恢复。
- 检查 CameraX 的
Camera.StateCallback日志,确保用例在后台真正关闭,前台重建后相机状态为OPEN。 - 使用
dumpsys media.camera确认后台时相机设备已被释放(无进程占用)。
4.6 常见错误
错误1:在 ON_STOP 中同步调用 get() 获取 CameraProvider
正确做法:使用
ProcessCameraProvider.getInstance(context) 返回 ListenableFuture,需异步注册回调,直接在生命周期方法中 .get() 会阻塞主线程造成 ANR。正确做法:使用
ListenableFuture.addListener(...) 或 Kotlin 协程 await()。
错误2:未处理多个 Activity 场景
若应用有多个 Activity,释放/恢复时需知晓当前前台 Activity 的 LifecycleOwner。建议构建一个全局 CameraXManager,内部维护弱引用指向当前可见 Activity 的 LifecycleOwner。
若应用有多个 Activity,释放/恢复时需知晓当前前台 Activity 的 LifecycleOwner。建议构建一个全局 CameraXManager,内部维护弱引用指向当前可见 Activity 的 LifecycleOwner。
经验:使用状态机避免竞争
前后台切换可能频繁触发 ON_STOP → ON_START 序列(例如快速切换应用)。建议在 CameraXManager 内部使用
前后台切换可能频繁触发 ON_STOP → ON_START 序列(例如快速切换应用)。建议在 CameraXManager 内部使用
StateMachine 或 AtomicBoolean 确保只有一次绑定/释放执行。
4.7 性能与稳定性优化
- 异步释放:释放 CameraProvider 时不要阻塞主线程,使用
ListenableFuture或Executors.newSingleThreadExecutor()处理关闭操作。 - 延迟恢复:应用回到前台后
ON_START可能紧接着 Activity 的onResume。建议在ON_START中只标记“需要恢复”,实际绑定操作交给当前 Activity 的onResume,保证 SurfaceProvider 已可用。 - 内存泄漏规避:ProcessLifecycleOwner 观察者生命周期与进程一致,观察者内部不要持有 Activity/Context 强引用,使用
ApplicationContext或弱引用。 - 前后台切换频率优化:若应用在短时间内连续切换(如指纹解锁),可通过
Handler.removeCallbacks合并多次释放/恢复操作。
4.8 全局生命周期与相机状态关系图
4.9 部署与验证清单
| 步骤 | 检查项 | 预期结果 |
|---|---|---|
| 1. 编译安装 | 应用无编译错误 | APK 安装成功 |
| 2. 前台运行 | CameraX 预览正常 | 画面流畅,无黑屏 |
| 3. 按下 Home 键 | 日志输出 "应用进入后台 → 释放相机" | CameraX 用例关闭 |
| 4. 从最近任务返回 | 日志输出 "应用回到前台 → 恢复相机" | 预览画面恢复,无延迟 |
| 5. 快速切换应用 | 无 ANR 或无重复绑定错误 | 应用稳定不闪退 |