You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter应用onResume返回相机页面触发PlatformException求助

Flutter相机扫码后台唤起崩溃问题

我使用mlkit-barcode库实现二维码扫描功能,借助flutter camera包完成图像捕获和实时预览,期望应用退至后台再返回后所有功能仍正常运行。当前通过didChangeLifecycleState回调处理生命周期,常规场景无异常,但执行以下流程后会崩溃:

  • 拍摄照片并跳转到第二个页面
  • 返回相机页面
  • 将应用退至后台再唤起
  • 实时预览、扫码及拍照功能全部失效

捕获的异常日志

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(error, Attempt to invoke virtual method 'android.view.Surface android.media.ImageReader.getSurface()' on a null object reference, null, java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.Surface android.media.ImageReader.getSurface()' on a null object reference

代码问题分析

  1. 页面返回逻辑错误:DisplayPictureScreen中使用pushReplacement重新创建TakePictureScreen,导致原页面实例未被正确销毁,其WidgetsBindingObserver仍会响应生命周期回调,新旧实例的相机控制器产生资源冲突。
  2. 生命周期处理不严谨:didChangeAppLifecycleState中未对控制器状态做细致判断,进入后台时直接销毁控制器,但唤起时的初始化流程未覆盖页面返回后的场景。
  3. 拍照后图像流未恢复:拍照时停止了图像流,但返回相机页面后未重新启动,后台唤起时也未处理该状态。

可行解决方案

1. 修复页面返回逻辑

移除DisplayPictureScreen中_onPopAsync的pushReplacement,改为直接返回上一页,避免重复创建页面实例:

Future<bool> _onPopAsync() async {
  Navigator.of(context).pop();
  return true;
}

2. 完善生命周期回调处理

增加控制器状态判断,避免无效操作,针对不同状态做精准处理:

@override
void didChangeAppLifecycleState(AppLifecycleState state) {
  log(state.name);
  final CameraController? cameraController = _controller;
  if (cameraController == null) return;

  if (state == AppLifecycleState.inactive) {
    log('inactive being called');
    cleanup();
  } else if (state == AppLifecycleState.resumed) {
    log('on resume called');
    if (_controller == null) {
      setUp();
    } else if (!_controller!.value.isInitialized) {
      _controller!.initialize().then((_) {
        if (mounted) {
          _controller?.startImageStream(_processCameraImage);
          setState(() {});
        }
      });
    } else if (!_controller!.value.isStreamingImages) {
      _controller?.startImageStream(_processCameraImage);
    }
  }
}

3. 拍照后恢复图像流

在拍照并返回相机页面后,重新启动图像流:

floatingActionButton: FloatingActionButton(
  onPressed: () async {
    try {
      if (!_controller!.value.isInitialized) {
        return;
      }

      await _controller!.stopImageStream();
      final image = await _controller!.takePicture();

      if (!mounted) return;

      await Navigator.of(context).push(
        MaterialPageRoute(
          builder: (context) => DisplayPictureScreen(imagePath: image.path),
        ),
      );

      // 返回后恢复图像流
      if (mounted && _controller != null && _controller!.value.isInitialized) {
        _controller?.startImageStream(_processCameraImage);
      }
    } catch (e) {
      print(e);
    }
  },
  child: const Icon(Icons.camera_alt),
),

4. 优化资源清理方法

确保资源释放彻底,避免空指针异常:

Future cleanup() async {
  _canProcess = false;
  _isBusy = false;
  await _barcodeScanner.close();
  if (_controller != null) {
    try {
      if (_controller!.value.isStreamingImages) {
        await _controller!.stopImageStream();
      }
      if (_controller!.value.isInitialized) {
        await _controller!.dispose();
      }
    } catch (e) {
      print(e);
    }
    _controller = null;
  }
}

内容的提问来源于stack exchange,提问作者Stelios Papamichail

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 04:20:35