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

Flutter应用调用相机功能后崩溃重启至启动页问题排查

解决方案:相机拍照后崩溃的问题分析与修复

从你提供的日志来看,崩溃的根源并不是相机或裁剪插件本身,而是SplashScreen页面的didChangeDependencies方法中出现了两个空指针错误,相机拍照后App回到前台触发了这些错误。下面是具体的分析和修复步骤:

1. 修复contains调用在null对象上的错误

日志第一条错误显示:

Unhandled Exception: NoSuchMethodError: The method 'contains' was called on null.
Receiver: null
Tried calling: contains("access_token")
#1 _SplashScreenState.didChangeDependencies (package:demo/screens/common/splash_screen.dart:58:28)

这说明你在SplashScreen的第58行,调用了一个未初始化的null变量的contains方法来检查"access_token"。

修复方式:

在调用contains前先判空,或者使用空安全操作符:

// 原代码(错误)
if (yourTokenString.contains("access_token")) { ... }

// 修复后方案一:先判空
if (yourTokenString != null && yourTokenString.contains("access_token")) { ... }

// 修复后方案二:使用空安全操作符(Dart 2.12+)
if (yourTokenString?.contains("access_token") ?? false) { ... }

2. 修复Navigator调用时context无效的问题

日志第二条错误显示:

Unhandled Exception: NoSuchMethodError: The method 'findAncestorStateOfType' was called on null.
Receiver: null
Tried calling: findAncestorStateOfType()
#2 _SplashScreenState.didChangeDependencies. (package:demo/screens/common/splash_screen.dart:54:23)

这是因为你在didChangeDependencies里的延迟Future中调用Navigator.of(context)时,当前SplashScreen Widget已经被dispose或者不再挂载在Widget树中(相机拍照会把App推到后台,回来时可能触发页面重建或销毁)。

修复方式:

在调用Navigator前先检查Widget是否还处于mounted状态:

// 原代码(错误)
Future.delayed(Duration(seconds: 2), () {
  Navigator.of(context).pushReplacementNamed("/home");
});

// 修复后
Future.delayed(Duration(seconds: 2), () {
  if (!mounted) return; // 先判断Widget是否还挂载
  Navigator.of(context).pushReplacementNamed("/home");
});

3. 优化相机拍照与裁剪的流程

你的getImage方法存在逻辑顺序问题:_pickInProgress的判断放在了拍照和裁剪之后,而且没有用try-finally确保状态重置,这可能导致异常后状态卡住。

修正后的getImage方法:

Future getImage() async {
  // 先判断是否正在处理,防止重复调用
  if (_pickInProgress) {
    return;
  }
  _pickInProgress = true;
  
  try {
    var _image = await ImagePicker.pickImage(source: ImageSource.camera);
    // 用户取消拍照时直接返回
    if (_image == null) {
      return;
    }
    
    croppedFile = await ImageCropper.cropImage(
      sourcePath: _image.path,
      aspectRatioPresets: [
        CropAspectRatioPreset.square,
        CropAspectRatioPreset.ratio3x2,
        CropAspectRatioPreset.original,
        CropAspectRatioPreset.ratio4x3,
        CropAspectRatioPreset.ratio16x9
      ],
      androidUiSettings: AndroidUiSettings(
        toolbarTitle: 'Cropper',
        toolbarColor: Colors.deepOrange,
        toolbarWidgetColor: Colors.white,
        initAspectRatio: CropAspectRatioPreset.square,
        lockAspectRatio: false),
      iosUiSettings: IOSUiSettings(
        minimumAspectRatio: 1.0,
      )
    );
    
    if (croppedFile != null) {
      setState(() {
        _newAvatar = croppedFile;
      });
    }
  } catch (e) {
    // 捕获异常,防止崩溃并打印日志
    print("拍照/裁剪过程出错: $e");
  } finally {
    // 无论成功或失败,都重置状态
    _pickInProgress = false;
  }
}

4. 额外检查:Android权限配置

确保你已经在AndroidManifest.xml中添加了必要的权限,并且在运行时请求了这些权限:

<!-- 在AndroidManifest.xml的<manifest>标签下添加 -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <!-- Android 13+ -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />

可以使用permission_handler插件来便捷地请求运行时权限,避免因权限不足导致的隐性异常。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 17:17:29