Android 10.0文件存储问题

Android10.0 临时解决方案

如果适配兼容10.0的文件存储比较麻烦,可以采用临时方案:


  
    
      ...
    

参考链接:https://developer.android.google.cn/training/data-storage/compatibility

自定义图片保存位置

Android10.0对文件存储方式改了,但是依然可以自定义存储位置,不过这个位置也是指定的文件夹下面自己生成新的文件夹以下是具体代码示例:

        String status = Environment.getExternalStorageState();
        // 判断是否有SD卡,优先使用SD卡存储,当没有SD卡时使用手机存储
        ContentValues contentValues = new ContentValues();
        contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
        contentValues.put(MediaStore.Images.Media.RELATIVE_PATH,"Pictures/img");
        if (status.equals(Environment.MEDIA_MOUNTED)) {
           return getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,contentValues );
        } else {
            return getContentResolver().insert(MediaStore.Images.Media.INTERNAL_CONTENT_URI, contentValues);
        }

在Android10.0上面使用MediaStore.Images.Media.RELATIVE_PATH来自定义位置(10.0之下还是要旧方式即可),后面是文件的路径,目录结构是以Pictures或者DCIM为开始,意思为只能创建在这两个目录下面,这两个是约定的公共目录(所以当保存其他类型的文件时候,这个目录可能就不是这个了)。当这个不在这两个目录下面时候,会出现类似与以下的错误:

   Process: com.donkingliang.photograph, PID: 18751
    java.lang.IllegalArgumentException: Primary directory dq not allowed for content://media/external/images/media; allowed directories are [DCIM, Pictures]
        at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:170)
        at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:140)
        at android.content.ContentProviderProxy.insert(ContentProviderNative.java:481)
        at android.content.ContentResolver.insert(ContentResolver.java:1844)
        at com.donkingliang.photograph.MainActivity.createImageUri(MainActivity.java:181)
        at com.donkingliang.photograph.MainActivity.openCamera(MainActivity.java:140)
        at com.donkingliang.photograph.MainActivity.checkPermissionAndCamera(MainActivity.java:81)
        at com.donkingliang.photograph.MainActivity.access$000(MainActivity.java:32)
        at com.donkingliang.photograph.MainActivity$1.onClick(MainActivity.java:67)
        at android.view.View.performClick(View.java:7161)
        at android.view.View.performClickInternal(View.java:7138)
        at android.view.View.access$3500(View.java:811)
        at android.view.View$PerformClick.run(View.java:27419)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:224)
        at android.app.ActivityThread.main(ActivityThread.java:7520)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)

参考链接:
https://developer.android.google.cn/training/data-storage/shared/media?hl=zh_cn#hint-file-location

Android中公共文件夹

由于Android10.0文件存储改版后,文件要存放到指定的位置。位置分为私有位置和共享位置。假如要存放到共享位置的外置存储空间时候。存放位置是要放在规定的位置的,这些空间主要有以下几种:

The system automatically scans an external storage volume and adds media files to the following well-defined collections:
Images, including photographs and screenshots, which are stored in the DCIM/ and Pictures/ directories. The system adds these files to the MediaStore.Images table.
Videos, which are stored in the DCIM/, Movies/, and Pictures/ directories. The system adds these files to the MediaStore.Video table.
Audio files, which are stored in the Alarms/, Audiobooks/, Music/, Notifications/, Podcasts/, and Ringtones/ directories, as well as audio playlists that are in the Music/ or Movies/ directories. The system adds these files to the MediaStore.Audio table.
Downloaded files, which are stored in the Download/ directory. On devices that run Android 10 (API level 29) and higher, these files are stored in the MediaStore.Downloads table. This table isn’t available on Android 9 (API level 28) and lower.
The media store also includes a collection called MediaStore.Files. Its contents depend on whether your app uses scoped storage, available on apps that target Android 10 or higher:
If scoped storage is enabled, the collection shows only the photos, videos, and audio files that your app has created.
If scoped storage is unavailable or not being used, the collection shows all types of media files.

参考链接:https://developer.android.com/training/data-storage/shared/media?hl=zh-cn

通过Uri获取文件名字

以前是通过File获取文件名字,改版后没有办法直接获取名字,通过Uri转文件再获取也比较麻烦,这里提供一个简单的方式

build.gradle:
 implementation 'androidx.documentfile:documentfile:1.0.1'

Mantivity.java:

 DocumentFile documentFile = DocumentFile.fromSingleUri(getBaseContext(), uri);
String fileName = documentFile .getName();
 Log.e("Y","文件名字:"+fileName);

通过Uri判断文件是否存在

以前是通过本地路径获取FIle后然后判断文件是否存在,但是Uri转换成File再进行判断会十分麻烦,因此这里还是使用Uri进行判断。什么时候会用到这个方式呢,比如缓存文件的判断,我们不能把Uri存储到本地,只能通过Uri转换成String存储到本地,然后使用的时候再转换为Uri进行读取。

build.gradle:
 implementation 'androidx.documentfile:documentfile:1.0.1'

Mantivity.java:

 DocumentFile documentFile = DocumentFile.fromSingleUri(getBaseContext(), uri);
 boolean exists = documentFile .exists();
 Log.e("Y","文件是否存在:"+exists);

Uri和String转换

Uri uri;
String localPath;
//localPath = uri.getPath();//这个不好用
 localPath = uri.toString();
uri = Uri.parser(localPath);

Uri转InputStream

Uri uri;
InputStream inputStream = getContext().getContentResolver().openInputStream(uri);

参考链接:
1、https://developer.android.google.cn/jetpack/androidx/releases/documentfile?hl=zh-cn
2、https://developer.android.google.cn/reference/androidx/documentfile/provider/DocumentFile?hl=zh-cn
3、各种文件的Content-Type的MIME_TYPE类型表:http://www.iana.org/assignments/media-types/media-types.xhtml

你可能感兴趣的:(Android,日常bug)