Flutter使用camera包调用Android相机抛出NoSuchMethodError异常求助
问题根因
你抛出的NoSuchMethodError: The method '[]' was called on null错误,来源于代码访问cameras[0]时,cameras全局变量还未完成初始化,仍为null值。
具体触发场景说明
- 你将
cameras = await availableCameras();移到initState中时,initState本身不支持异步等待,代码执行到controller = CameraController(cameras[0],...)时,availableCameras的异步操作还未完成,cameras还没有被赋值,直接触发空值调用错误。 - 你最初版本可正常运行,是因为最初的main函数中补全了
WidgetsFlutterBinding.ensureInitialized()的调用,Flutter框架初始化完成后才执行availableCameras获取相机列表,保证cameras在使用前已经完成赋值。
修复方案
第一步:补全平台权限配置
Android端
在android/app/src/main/AndroidManifest.xml的manifest标签下添加相机权限:
<uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" />
iOS端
在ios/Runner/Info.plist的dict标签下添加相机权限说明:
<key>NSCameraUsageDescription</key> <string>需要使用相机完成考勤打卡</string>
第二步:修复代码逻辑
这里提供两种稳定实现方案:
方案1:保留全局相机列表初始化逻辑
在main函数中补全Flutter绑定初始化的调用,保证相机列表获取操作在框架初始化完成后执行:
Future<void> main() async { // 新增代码,必须放在所有异步操作之前 WidgetsFlutterBinding.ensureInitialized(); cameras = await availableCameras(); runApp(MyApp()); }
同时在CameraAppState的build方法中补全空判断,避免极端场景下的空指针:
@override Widget build(BuildContext context) { // 新增controller非空判断 if (controller == null || !controller.value.isInitialized) { return const Center(child: CircularProgressIndicator()); } return RotationTransition( turns: AlwaysStoppedAnimation(270 / 360), child: CameraPreview(controller), ); }
方案2:将相机初始化逻辑全部移入State中(更稳定,避免全局变量风险)
先删除全局的List<CameraDescription> cameras;定义,修改CameraAppState的代码:
class CameraAppState extends State<CameraApp> { CameraController? controller; // 改为可空类型 @override void initState() { super.initState(); _initCamera(); } // 独立的异步初始化方法 Future<void> _initCamera() async { // 若使用permission_handler包,可在此处先申请相机权限 final cameras = await availableCameras(); if (cameras.isEmpty) return; controller = CameraController(cameras[0], ResolutionPreset.medium); await controller?.initialize(); if (mounted) setState(() {}); } @override void dispose() { controller?.dispose(); super.dispose(); } @override Widget build(BuildContext context) { if (controller == null || !controller!.value.isInitialized) { return const Center(child: CircularProgressIndicator()); } return RotationTransition( turns: const AlwaysStoppedAnimation(270 / 360), child: CameraPreview(controller!), ); } }
验证说明
修复完成后完全关闭应用进程重新运行,不要使用热重载,避免旧的状态残留导致异常。
内容的提问来源于stack exchange,提问作者Tri yulianto
相关产品推荐
相关产品推荐

