Flutter中CameraController初始化失败:空值检查运算符报错
问题:Bloc模式下相机预览触发Null check错误
我使用Bloc模式构建相机访问功能,打开相机预览页面时出现错误:"Null check operator used on a null value",空值指向CameraController。我认为问题出在CameraController未在调用前完成初始化。
工具类CameraUtils代码
class CameraUtils { Future<CameraController> getCameraController( ResolutionPreset resolutionPreset) async { final cameras = await availableCameras(); final camera = cameras.first; return CameraController( camera, resolutionPreset, imageFormatGroup: ImageFormatGroup.bgra8888, ); } Future<String> getPath() async => join( (await getTemporaryDirectory()).path, '${DateTime.now()}.png', ); }
CameraBloc类代码
class CameraBloc extends Bloc<CameraEvent, CameraState> { late final CameraUtils _cameraUtils; late final ResolutionPreset _resolutionPreset; late final CameraLensDirection _cameraLensDirection; CameraController? _controller; late File pictureTaken; CameraBloc() : super(CameraInitial()) { _cameraUtils = CameraUtils(); _resolutionPreset = ResolutionPreset.high; _cameraLensDirection = CameraLensDirection.back; on<CameraInitialized>(_onCameraInitialized); on<CameraCaptured>(_onCameraCaptured); on<CameraStopped>(_onCameraStopped); add(CameraInitialized()); } Stream<CameraState> _onCameraInitialized( CameraInitialized event, emit) async* { try { _controller = await _cameraUtils.getCameraController(_resolutionPreset); await _controller!.initialize(); yield CameraReady(); } on CameraException catch (error) { _controller!.dispose(); yield CameraFailure(error: error.description ?? "Camera generic error"); } catch (error) { yield CameraFailure(error: error.toString()); } } Stream<CameraState> _onCameraCaptured(CameraCaptured event, emit) async* { if (state is CameraReady) { yield CameraCaptureInProgress(); try { final path = await _cameraUtils.getPath(); await _controller?.takePicture(); yield CameraCaptureSuccess(path: path); } on CameraException catch (error) { yield CameraCaptureFailure( error: error.description ?? "Generic camera capture failure"); } } } Stream<CameraState> _onCameraStopped(CameraStopped event, emit) async* { _controller?.dispose(); yield CameraInitial(); } void initController() async { _controller = await _cameraUtils.getCameraController(_resolutionPreset); await _controller!.initialize(); } CameraController getController() => _controller!; void getCamera() => add(CameraInitialized()); }
CameraView代码
class CameraView extends StatefulWidget { const CameraView({Key? key}) : super(key: key); @override State<CameraView> createState() => _CameraViewState(); } class _CameraViewState extends State<CameraView> { @override Widget build(BuildContext context) { return CameraPreview(BlocProvider.of<CameraBloc>(context).getController()); } }
解决方案
1. 基于Bloc状态安全渲染相机预览
修改CameraView,通过BlocBuilder监听Bloc状态,仅当状态为CameraReady时渲染CameraPreview,其他状态显示加载或错误界面:
class CameraView extends StatefulWidget { const CameraView({Key? key}) : super(key: key); @override State<CameraView> createState() => _CameraViewState(); } class _CameraViewState extends State<CameraView> { @override Widget build(BuildContext context) { return BlocBuilder<CameraBloc, CameraState>( builder: (context, state) { if (state is CameraReady) { return CameraPreview(context.read<CameraBloc>().getController()); } else if (state is CameraInitial || state is CameraCaptureInProgress) { return const Center(child: CircularProgressIndicator()); } else if (state is CameraFailure || state is CameraCaptureFailure) { return Center(child: Text((state as dynamic).error)); } return const SizedBox.shrink(); }, ); } }
2. 修复Bloc中的空安全隐患
- 在
_onCameraInitialized的异常捕获中,将_controller!.dispose()改为_controller?.dispose(),避免_controller为null时触发空检查:
Stream<CameraState> _onCameraInitialized( CameraInitialized event, emit) async* { try { _controller = await _cameraUtils.getCameraController(_resolutionPreset); await _controller!.initialize(); yield CameraReady(); } on CameraException catch (error) { _controller?.dispose(); // 改为可选链调用 yield CameraFailure(error: error.description ?? "Camera generic error"); } catch (error) { _controller?.dispose(); // 新增:确保异常时释放资源 yield CameraFailure(error: error.toString()); } }
- 可以修改
getController()方法,增加状态判断或返回可空类型,避免强制解包:
CameraController? getController() => _controller; // 或者在状态为CameraReady时才返回 CameraController? getController() { if (state is CameraReady) { return _controller; } return null; }
3. 确保Bloc初始化逻辑的异步顺序
Bloc构造函数中添加的CameraInitialized事件是异步处理的,页面加载时Bloc可能仍处于CameraInitial状态,此时_controller尚未初始化。通过BlocBuilder监听状态变化,能确保只有在CameraReady状态下才访问CameraController,从根源避免空值问题。
内容的提问来源于stack exchange,提问作者Finley Adams
相关产品推荐
相关产品推荐

