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

使用ActivityResultLauncher从相册选图上传头像选择后闪退如何解决

问题根因

  • 你当前写法错误获取返回的图片Uri:ACTION_PICK返回的选中图片Uri直接存在返回的Intent对象本身,不是存到Extras里的,你调用data.get("data")拿到的是null,后续赋值就会触发空指针闪退。
  • 缺少Uri持久化授权:Android系统返回的相册Uri默认是临时权限,应用退到后台/重启后再访问会报错,需要主动申请持久化权限才能长期存在数据库里用。
  • 缺少动态权限申请:Android 6.0+需要动态申请存储权限,Android13+需要申请READ_MEDIA_IMAGES权限,权限缺失也会触发闪退。

完整修改方案

第一步:添加权限声明(AndroidManifest.xml)

<!-- Android 12及以下存储权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<!-- Android 13及以上图片权限 -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

第二步:修改业务代码(更推荐直接用GetContent协议,无需手动构造Intent)

// 初始化图片选择器
ActivityResultLauncher<String> imagePickerLauncher = registerForActivityResult(
        new ActivityResultContracts.GetContent(),
        uri -> {
            if (uri != null) {
                // 申请Uri持久化权限,方便后续存数据库后长期访问
                final int takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION;
                getContentResolver().takePersistableUriPermission(uri, takeFlags);
                // 赋值给头像控件
                profilePic.setImageURI(uri);
                // 这里可以把uri.toString()存到你的用户数据库里
                String saveUriStr = uri.toString();
            }
        }
);

// 上传按钮点击逻辑
uploadPicture.setOnClickListener(view -> {
    if (checkStoragePermission()) {
        imagePickerLauncher.launch("image/*");
    } else {
        requestStoragePermission();
    }
});

第三步:补充权限检查辅助方法

private boolean checkStoragePermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        return ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_IMAGES) == PackageManager.PERMISSION_GRANTED;
    } else {
        return ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
    }
}

private void requestStoragePermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_MEDIA_IMAGES}, 1001);
    } else {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1001);
    }
}

// 权限申请回调
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == 1001) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            imagePickerLauncher.launch("image/*");
        }
    }
}

若要保留原有StartActivityForResult写法,仅修改返回处理逻辑即可

activityResultLauncher = registerForActivityResult(
        new ActivityResultContracts.StartActivityForResult(), result -> {
            if (result.getResultCode() == RESULT_OK && result.getData() != null) {
                // 直接从Intent拿Uri,不要读取Extras
                Uri myUri = result.getData().getData();
                if (myUri != null) {
                    // 同样申请持久化权限
                    final int takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION;
                    getContentResolver().takePersistableUriPermission(myUri, takeFlags);
                    profilePic.setImageURI(myUri);
                }
            }
        });

额外注意

  • setImageURI是在UI线程直接加载图片,如果选的原图很大可能会导致卡顿或者ANR,实际生产环境建议用Glide、Coil等图片加载框架加载Uri到头像控件,自动处理采样压缩。
  • 存数据库的时候存uri.toString()的字符串就行,后续要使用的时候用Uri.parse(uriStr)转回Uri对象即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 22:15:05