Android 10 开始 启动了分区存储,在开发的时候,就需要进行一些适配,以下是需要适配的一下方法
1. 项目中使用了 选择图片功能,所以选择了 https://github.com/zhihu/Matisse
2. 图片展示:
采用了分区存储,之前的 通过path 展示图片的时候,会发现图片无法展示了(除了自己app的存储内的文件)
所有在选择图片的回来后,不使用 path 而是使用 Uri
Set s = new HashSet<>();
s.add(MimeType.PNG);
s.add(MimeType.JPEG);
Matisse.from(ImagePickerActivity.this)
.choose(s)
.countable(false)
.maxSelectable(1)
.thumbnailScale(1)
.imageEngine(new PicassoEngine())
.showPreview(false) // Default is `true`
.showSingleMediaType(true)
.forResult(121);
返回的时候,注意返回 Uri
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 121 && resultCode == RESULT_OK) {
List imagePaths = Matisse.obtainResult(data);
}
}
通过uri 使用Glide 加载图片就可以。
3. 如果只有 path 要去查 图片的 Uri 咋办呢?
public static Uri getImageContentUri(String path) {
Cursor cursor = MyApplication.getApplication().getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Images.Media._ID}, MediaStore.Images.Media.DATA + "=? ",
new String[]{path}, null);
if (cursor != null && cursor.moveToFirst()) {
int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
Uri baseUri = Uri.parse("content://media/external/images/media");
return Uri.withAppendedPath(baseUri, "" + id);
} else {
// 如果图片不在手机的共享图片数据库,就先把它插入。
if (new File(path).exists()) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DATA, path);
return MyApplication.getApplication().getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} else {
return null;
}
}
}
4. 如果需要操作这个图片转bitmap又咋办呢?
可以通过Uri 转bitmap ,但是 对于稍大的图片 会很卡,甚至出现 OOM,所有我舍弃了这个方法,采用了,将图片通过复制到app 的存储路径,再进行随心所欲的操作
@SuppressLint("NewApi")
public static File copyFile(final Uri uri) {
File file = null;
if(uri == null) return file;
//android10以上转换
if (uri.getScheme().equals(ContentResolver.SCHEME_FILE)) {
file = new File(uri.getPath());
} else if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
//把文件复制到沙盒目录
ContentResolver contentResolver = MyApplication.getApplication().getContentResolver();
String displayName = System.currentTimeMillis()+ Math.round((Math.random() + 1) * 1000)
+"."+ MimeTypeMap.getSingleton().getExtensionFromMimeType(contentResolver.getType(uri));
try {
InputStream is = contentResolver.openInputStream(uri);
File cache = new File(MyApplication.getApplication().getExternalCacheDir().getAbsolutePath(), displayName);
FileOutputStream fos = new FileOutputStream(cache);
FileUtils.copy(is, fos);
file = cache;
fos.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return file;
}
上述代码中
getExternalCacheDir().getAbsolutePath()
是将文件复制到
/storage/emulated/0/Android/data/xxxxx/cache
此处可根据需求进行改动
注意:在调用FileUtiles.copy 时需要注意
Build.VERSION.SDK_INT < Build.VERSION_CODES.Q
如果版本是10 以下,就可以直接 使用
Bitmap bitmap = BitmapFactory.decodeFile(imagePath); // file转bitmap
如果是 10 以上,还需要判断,是不是 在自己app 的文件夹内,true,直接 使用 file 转bitmap
fase 调用复制,再使用 file 转bitmap
5. 现在有个需求,需要将图片插入相册咋办呢?
@SuppressLint("NewApi")
public static String bitmapToFileToAl(Context context, Bitmap bmp) {
Long mImageTime = System.currentTimeMillis();
String timeStamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS")
.format(new Date(mImageTime));
final ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES
+ File.separator + "cck"); //Environment.DIRECTORY_SCREENSHOTS:截图,图库中显示的文件夹名。"dh"
values.put(MediaStore.MediaColumns.DISPLAY_NAME, timeStamp);
values.put(MediaStore.MediaColumns.MIME_TYPE, "image/png");
values.put(MediaStore.MediaColumns.DATE_ADDED, mImageTime / 1000);
values.put(MediaStore.MediaColumns.DATE_MODIFIED, mImageTime / 1000);
values.put(MediaStore.MediaColumns.DATE_EXPIRES, (mImageTime + DateUtils.DAY_IN_MILLIS) / 1000);
values.put(MediaStore.MediaColumns.IS_PENDING, 1);
ContentResolver resolver = context.getContentResolver();
final Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
try {
// First, write the actual data for our screenshot
try (OutputStream out = resolver.openOutputStream(uri)) {
if (!bmp.compress(Bitmap.CompressFormat.PNG, 100, out)) {
throw new IOException("Failed to compress");
}
}
// Everything went well above, publish it!
values.clear();
values.put(MediaStore.MediaColumns.IS_PENDING, 0);
values.putNull(MediaStore.MediaColumns.DATE_EXPIRES);
resolver.update(uri, values, null, null);
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getPath() + "\\cck\\" + timeStamp + ".png";
} catch (IOException e) {
resolver.delete(uri, null);
Log.d("Exception", e.toString());
}
return "";
}
6. 另外
android:requestLegacyExternalStorage="true"
android:preserveLegacyExternalStorage="true"
总结: