4. ProcessLifecycleOwner 场景应用:全局应用前后台切换时相机释放与恢复

4.1 原理

Activity 或 Fragment 的 LifecycleOwner 只能感知自身组件的生命周期,无法覆盖应用全局的前后台切换(如用户按下 Home 键后再返回)。ProcessLifecycleOwner 是 Android Lifecycle 库提供的全局生命周期观测者,它代表整个应用进程的生命周期,可监听 ON_START(应用进入前台)和 ON_STOP(应用进入后台)。利用这一能力,开发者能在应用切到后台时立即释放 CameraX 相机资源(避免后台占用摄像头导致系统杀进程或其他应用无法使用),并在切回前台时安全恢复相机。

4.2 实现流程

  1. 在 app 模块 build.gradle 添加 lifecycle-process 依赖。
  2. 在 Application 类或任意组件中获取 ProcessLifecycleOwner 实例。
  3. 注册 LifecycleObserver 监听 ON_START 和 ON_STOP 事件。
  4. 在 ON_STOP 中调用 ProcessCameraProvider.getInstance(context).get() 获取 CameraProvider 并关闭所有用例。
  5. 在 ON_START 中重新绑定预览/分析等用例(参考标准 CameraX 启动流程)。
  6. 使用 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。
经验:使用状态机避免竞争
前后台切换可能频繁触发 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 全局生命周期与相机状态关系图

ProcessLifecycleOwner 监听应用前后台切换 应用前台运行 CameraX 正常绑定 ON_STOP 事件 应用进入后台 释放 CameraProvider 关闭所有用例 ON_START 事件 应用回到前台 重新绑定 CameraX 用例 生命周期循环 提示:使用AtomicBoolean防重复执行 ON_START 可能因旋转屏幕多次触发

4.9 部署与验证清单

步骤检查项预期结果
1. 编译安装应用无编译错误APK 安装成功
2. 前台运行CameraX 预览正常画面流畅,无黑屏
3. 按下 Home 键日志输出 "应用进入后台 → 释放相机"CameraX 用例关闭
4. 从最近任务返回日志输出 "应用回到前台 → 恢复相机"预览画面恢复,无延迟
5. 快速切换应用无 ANR 或无重复绑定错误应用稳定不闪退