安卓14更换头像相册使用若干问题包含权限问题以及系统裁剪报错Mutation of _data is not allowed解决并兼容各个版本

最近发现再安卓14的系统上,用户无法正常使用相册图片更换头像
问题一
相册空白(权限问题)
解决方案
添加关键动态权限READ_MEDIA_VISUAL_USER_SELECTED
mainfest仍然需要添加权限

<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
    <uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED"
        android:minSdkVersion="34" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
        android:maxSdkVersion="32" />

权限动态代码(此处用谷歌EasyPermissions框架,其它框架用法类似,回调省略。。。)

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
            String[] perms32 = {
                    Manifest.permission.READ_MEDIA_IMAGES,
                    Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
            };
            if (!EasyPermissions.hasPermissions(this, perms32)){
                EasyPermissions.requestPermissions(this, getString(R.string.permission_request),
                        READ_MEDIA_IMAGES, perms32);
            }
        } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.TIRAMISU) {
            //录音下一个版本在开发
            String[] perms32 = {
                    Manifest.permission.READ_MEDIA_IMAGES
            };
            if (!EasyPermissions.hasPermissions(this, perms32)){
                EasyPermissions.requestPermissions(this, getString(R.string.permission_request),
                        READ_MEDIA_IMAGES, perms32);
            }
        } else {
            String[] perms = {
                    Manifest.permission.READ_EXTERNAL_STORAGE,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE};
            if (!EasyPermissions.hasPermissions(this, perms)){
                EasyPermissions.requestPermissions(this, getString(R.string.permission_request),
                        READ_EXTERNAL_STORAGE, perms);
                        //以上代码兼容各个版本,已经不需要单独兼容安卓11,故以下代码废弃
//            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
//                Uri uri = Uri.parse("package:" + getPackageName());
//                startActivity(new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, uri));
//            }
            }
        }

此处就是当选择图片以后 进入系统裁剪
特别说明 Global.setCropPhotoFilePath(imgFile.getAbsolutePath());
全局保存图片的路径,系统裁剪完成之后这个路径就是裁剪后的图片。
此处可以自行优化,安卓13以后,外部存储已经指定了的图片存储位置,只需要知道图片名,即可找到文件

 //支持安卓各种版本的裁剪功能
    public static void startIconPhotoCrop(Activity context, Uri sourceUri) {
        File imgFile;
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.putExtra("crop", "true");
        intent.putExtra("aspectX", 1);    //X方向上的比例
        intent.putExtra("aspectY", 1);    //Y方向上的比例
        intent.putExtra("outputX", 256);  //裁剪区的宽
        intent.putExtra("outputY", 256); //裁剪区的高
        intent.putExtra("scale ", true);  //是否保留比例
        intent.putExtra("return-data", false);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        intent.setDataAndType(sourceUri, "image/*"); //设置数据源
        Uri uri;
        try {
//            String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
            String uuid = AndroidUtil.getUUID().replace("-","");
            String fileName = "CROP_"+ uuid +".jpg";
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                imgFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + File.separator + fileName);
                ContentValues values = new ContentValues();
                values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
                values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
                values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
                Uri externalUri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
                uri = context.getContentResolver().insert(externalUri, values);
            } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {
                imgFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + File.separator + fileName);
                // 通过 MediaStore API 插入file 为了拿到系统裁剪要保存到的uri(因为App没有权限不能访问公共存储空间,需要通过 MediaStore API来操作)
                ContentValues values = new ContentValues();
                //安卓13起不能使用MediaStore.Images.Media.DATA否则会报错Mutation of _data is not allowed
                values.put(MediaStore.Images.Media.DATA, imgFile.getAbsolutePath());
                values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
                values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
                uri = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
            } else {
                imgFile = FileManager.ofMedia(fileName);
                uri = Uri.fromFile(imgFile);
            }
            intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
            Global.setCropPhotoFilePath(imgFile.getAbsolutePath());
            context.startActivityForResult(intent, Constant.RESULT_ZOOM);
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值