Android分区存储相关

参考链接https://blog.csdn.net/guolin_blog/article/details/105419420/

Android 10 作用域存储(分区存储)

Android的外置存储特点

  • 存储在SD卡的文件不会计入到应用程序的占用空间当中,也就是说即使你在SD卡存放了1G的文件,你的应用程序在设置中显示的占用空间仍然可能只有几十K。
  • 存储在SD卡的文件,即使应用程序被卸载了,这些文件仍然会被保留下来,这有助于实现一些需要数据被永久保留的功能。

对用户的影响

  • 这会将用户的SD卡空间搞得乱糟糟的,而且即使卸载一个完全不再使用的程序,它所产生的垃圾文件却可能会一直保留在我的手机上。
  • 存储在SD卡上的文件属于公有文件,所有的应用程序都有权随意访问,这也对数据的安全性带来了很大的挑战。

Android的分区存储特点

  • 从Android 10开始,每个应用程序只能有权在自己的外置存储空间关联目录下读取和创建文件
  • 读取手机相册的内容(图片、音频、视频),要使用MediaStore来进行访问,访问其他文件要通过系统的文件选择器。
  • 自己的应用向手机媒体库提供的内容可以不申请权限直接访问,但是要访问媒体库其他内容就要申请READ_EXTERNAL_STORAGE。
  • WRITE_EXTERNAL_STORAGE权限将会在未来的Android版本中废弃

适配问题

  • 对于targetSdkVersion < 29 的应用来说可以不做分区存储的适配,也可以正常运行在Android10的手机上。
  • 对于targetSdkVersion >= 29 的应用来说可以在Manifest中申请android:requestLegacyExternalStorage="true"
    这只是一种权宜之计,在未来的Android系统版本中,这段配置随时都可能会失效。

获取相册中的图片示例

  • 申请读取权限
// 从图库中挑选一张图片 并返回图片的uri
Intent  intent = new Intent(Intent.ACTION_PICK);
        intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
        startActivityForResult(intent, GET_PIC);

        // uri为onActivityResult()成功返回的Intent.getData;
        ImageDecoder.Source source = ImageDecoder.createSource(getContext().getContentResolver(), uri);
        Drawable drawable = ImageDecoder.decodeDrawable(source);
        fragmentBlinkBinding.rlBackPic.setBackground(drawable);
//打印图库中所有图片的uri
 ContentResolver contentResolver = getContentResolver();
        Cursor query = contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null);
        if(query != null){
            while (query.moveToNext()){
                long id = query.getLong(query.getColumnIndexOrThrow(MediaStore.MediaColumns._ID));
                Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);
                System.out.println(uri);
            }
            query.close();
        }
//uri示例
content://media/external/images/media/195430

拿到uri以后显示图片操作举例

  • 使用Glide加载图片
Glide.with(context).load(uri).into(imageView);
  • 使用ImageDecoder类
        @RequiresApi(api = Build.VERSION_CODES.P)
        ImageDecoder.Source source = ImageDecoder.createSource(getContext().getContentResolver(), uri);
        Drawable drawable = ImageDecoder.decodeDrawable(source);
        fragmentBlinkBinding.rlBackPic.setBackground(drawable);
  • 使用Bitmap
        ParcelFileDescriptor r = contentResolver.openFileDescriptor(uri, "r");
        Bitmap bitmap = BitmapFactory.decodeFileDescriptor(r.getFileDescriptor());
        r.close();
        imageView.setImageBitmap(bitmap);

从网络加载一张图片放入图库

索引 含义 是否必须
DISPLAY_NAME 文件名称
MIME_TYPE 文件类型
RELATIVE_PATH 相对路径 跟绝对路径二选一
MediaStore.MediaColumns.DATA 绝对路径 跟相对路径二选一
MIME_TYPE 可以通过查询
   ContentValues contentValues = new ContentValues();
                contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, "aa.png");
                contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/png");
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
                    contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM);
                else
                    contentValues.put(MediaStore.MediaColumns.DATA, Environment.getExternalStorageDirectory().getPath() + "/" + Environment.DIRECTORY_DCIM + "/" + "");
                // 插入图片的uri,此时文件为空
                Uri insert = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
                if (insert != null) {
                    try {
                      URL url = new URL("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603617504519&di=9b6a431f0de43d87593286bd0f79e504&imgtype=0&src=http%3A%2F%2Fh.hiphotos.baidu.com%2Fzhidao%2Fpic%2Fitem%2F0dd7912397dda144dac4acc9b2b7d0a20df486f8.jpg");
                        try (OutputStream outputStream = getContentResolver().openOutputStream(insert); InputStream inputStream = url.openStream()) {
                            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
                            BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
                            byte[] bytes = new byte[1024];
                            int var;
                            while ((var = bufferedInputStream.read(bytes)) >= 0) {
                                bufferedOutputStream.write(bytes,0,var);
                                bufferedOutputStream.flush();
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    } catch (MalformedURLException e) {
                        e.printStackTrace();
                    }
                }
            }

DIRECTORY_MUSIC 音乐目录

DIRECTORY_PICTURES 图片目录

DIRECTORY_MOVIES 电影目录

DIRECTORY_DOWNLOADS 下载目录

DIRECTORY_DCIM 相机拍照或录像文件的存储目录

DIRECTORY_DOCUMENTS 文件文档目录

存储技巧就是可以在存储时直接将自己应用的所有图片放在同一个文件夹下,只需修改路径在DCIM+"/"+"自己的文件夹名字"+"/"。

原文地址:https://www.cnblogs.com/FCY-LearningNotes/p/13873394.html