You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Flutter CameraPlugin:CameraPreview切后台恢复后冻结问题咨询

Flutter CameraPreview后台恢复后冻结的问题分析与解决

遇到这种后台切换回来相机预览冻结的情况,核心原因是你的CameraController没有正确响应APP的生命周期变化。虽然你提到已经在页面销毁时正确释放了控制器,但忽略了APP前后台切换时相机会话的管理逻辑。

问题根源

当APP切换到后台时,Android/iOS系统会主动暂停相机硬件会话来节省资源或避免冲突,但CameraController并不会自动在APP回到前台时恢复会话。如果没有手动处理这个状态变化,就会出现预览画面冻结的情况。

解决方案:监听生命周期并处理相机会话

我们可以通过混入WidgetsBindingObserver来监听APP的生命周期状态,在后台时主动暂停预览,前台时恢复或重新初始化相机。

以下是修改后的完整代码示例:

class CameraPage extends StatefulWidget {
  @override
  _CameraPageState createState() => _CameraPageState();
}

class _CameraPageState extends State<CameraPage> with WidgetsBindingObserver {
  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
  CameraController? _controller;
  Future<void>? _initializeControllerFuture;
  bool isCameraReady = false;

  @override
  void initState() {
    super.initState();
    // 注册生命周期监听
    WidgetsBinding.instance.addObserver(this);
    _initializeCamera();
  }

  Future<void> _initializeCamera() async {
    final cameras = await availableCameras();
    final firstCamera = cameras.first;
    _controller = CameraController(firstCamera, ResolutionPreset.high);
    _initializeControllerFuture = _controller?.initialize();
    if (!mounted) {
      return;
    }
    setState(() {
      isCameraReady = true;
    });
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    // 控制器未初始化时直接返回
    if (_controller == null || !_controller!.value.isInitialized) {
      return;
    }

    if (state == AppLifecycleState.paused) {
      // APP进入后台时暂停预览
      _controller?.pausePreview();
    } else if (state == AppLifecycleState.resumed) {
      // APP回到前台时恢复预览,失败则重新初始化
      _controller?.resumePreview().catchError((_) {
        _initializeCamera();
      });
    }
  }

  @override
  void dispose() {
    // 注销生命周期监听,避免内存泄漏
    WidgetsBinding.instance.removeObserver(this);
    // 释放相机控制器
    _controller?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      body: Stack(
        children: <Widget>[
          FutureBuilder<void>(
            future: _initializeControllerFuture,
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.done) {
                return CameraPreview(_controller!);
              } else {
                return const Center(child: CircularProgressIndicator());
              }
            },
          ),
        ],
      ),
    );
  }
}

关键细节说明

  1. 生命周期监听注册/注销:在initState中注册监听,dispose中注销,避免内存泄漏。
  2. 异常处理:在恢复预览时加入catchError,因为系统可能已经回收了相机资源,直接恢复会失败,此时需要重新初始化控制器。
  3. 控制器判空:所有控制器操作前都做判空处理,防止页面销毁后调用方法导致崩溃。

内容的提问来源于stack exchange,提问作者Navin Kumar

火山引擎 最新活动