Android 10.0文件存儲問題

Android10.0 臨時解決方案

如果適配兼容10.0的文件存儲比較麻煩,可以採用臨時方案:

<manifest ... >
  <!-- This attribute is "false" by default on apps targeting
       Android 10 or higher. -->
    <application android:requestLegacyExternalStorage="true" ... >
      ...
    </application>
</manifest>

參考鏈接: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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章