在 asynctask 期间未授予 Android 存储访问框架持久权限

Lar*_*rry 3 permissions android android-asynctask android-bitmap

我在这里设置了意图标志:

\n\n
public void createAlbum(View view) {\n    Intent intent = new Intent();\n    intent.setType("image/*");\n    intent.setAction(Intent.ACTION_OPEN_DOCUMENT);\n    intent.addCategory(Intent.CATEGORY_OPENABLE);\n    intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);\n    intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);\n    String intentChooserDialog = getResources().getString(R.string.pick_image_dialog);\n    startActivityForResult(Intent.createChooser(intent, intentChooserDialog), PICK_IMAGE);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

在我的活动结果中,我设置了持久权限,如下所述

\n\n
@Override\nprotected void onActivityResult(int requestCode, int resultCode, Intent data) {\n    super.onActivityResult(requestCode, resultCode, data);\n    if (requestCode == PICK_IMAGE) {\n        // Get image selection\n        if (data != null) {\n            ClipData clipData = data.getClipData();\n            if (clipData != null) {\n                int clipDataCount = clipData.getItemCount();\n                if (clipDataCount > 1) {\n                    int clipIndex = 0;\n                    BitmapUri[] bitmapUris = new BitmapUri[clipDataCount];\n                    while (clipIndex < clipDataCount) {\n                        ClipData.Item item = clipData.getItemAt(clipIndex);\n                        Uri uri = item.getUri();\n                        int takeFlags = data.getFlags();\n                        takeFlags &= Intent.FLAG_GRANT_READ_URI_PERMISSION;\n                        getContentResolver().takePersistableUriPermission(uri, takeFlags);\n                        BitmapUri bitmapUri = new BitmapUri(Uri.decode(uri.toString()),            data.getFlags());\n                        bitmapUris[clipIndex] = bitmapUri;\n                        clipIndex++;\n                    }\n                    DatabaseAlbumWriter dab = new DatabaseAlbumWriter(this);\n                    dab.execute(bitmapUris);\n                }\n            } else {\n                int oneImageSelected = 1;\n                BitmapUri[] bitmapUris = new BitmapUri[oneImageSelected];\n                Uri uri = data.getData();\n                int takeFlags = data.getFlags();\n                takeFlags &= Intent.FLAG_GRANT_READ_URI_PERMISSION;\n                getContentResolver().takePersistableUriPermission(uri, takeFlags);\n                BitmapUri bitmapUri = new BitmapUri(Uri.decode(uri.toString()), data.getFlags());\n                bitmapUris[0] = bitmapUri;\n                DatabaseAlbumWriter dab = new DatabaseAlbumWriter(this);\n                dab.execute(bitmapUris[0]);\n            }\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

将内容样式 Uri\xe2\x80\x99s 保存到 sqlite3 数据库后,我想将它们加载到 gridview 中,但按照此处所述异步加载所述异步加载。这是我在培训指南中实现的decodeSampledBitmapFromResource。传入一个带有解码后的 Uri 字符串和原始意图的持久权限的对象。这些值被保存在数据库中并再次加载到此处。

\n\n
        protected Bitmap decodeSampledBitmapFromResource(BitmapUri bitmapUri, int reqWidth, int reqHeight) {\n        Bitmap bitmap = null;\n        Uri uri = Uri.parse(bitmapUri.getStringUri());\n        int permissions = bitmapUri.getPermissions();\n        permissions &= Intent.FLAG_GRANT_READ_URI_PERMISSION;\n        try {\n            getContentResolver().takePersistableUriPermission(uri, permissions);\n            ParcelFileDescriptor parcelFileDescriptor = getContentResolver().openFileDescriptor(uri, "r");\n            FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();\n            // First decode with inJustDecodeBounds=true to check dimensions\n            final BitmapFactory.Options options = new BitmapFactory.Options();\n            options.inJustDecodeBounds = true;\n            Rect rect = new Rect(-1,-1,-1,-1);\n            BitmapFactory.decodeFileDescriptor(fileDescriptor, rect, options);\n            // Calculate inSampleSize\n            options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);\n            // Decode bitmap with inSampleSize set\n            options.inJustDecodeBounds = false;\n            bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor, rect, options);\n            parcelFileDescriptor.close();\n        } catch (NullPointerException | SecurityException | IOException e) {\n            e.printStackTrace();\n        }\n        return bitmap;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

正是在这里我收到了这个错误:

\n\n
05-08 14:17:40.850 2728-2813/com.example.app W/System.err: java.lang.SecurityException: No persistable permission grants found for UID 10058 and Uri 0 @ content://com.android.providers.media.documents/document/image:32\n05-08 14:17:40.850 2728-2813/com.example.app W/System.err:     at android.os.Parcel.readException(Parcel.java:1599)\n05-08 14:17:40.850 2728-2813/com.example.app W/System.err:     at android.os.Parcel.readException(Parcel.java:1552)\n05-08 14:17:40.850 2728-2813/com.example.app W/System.err:     at android.app.ActivityManagerProxy.takePersistableUriPermission(ActivityManagerNative.java:4217)\n05-08 14:17:40.850 2728-2813/com.example.app W/System.err:     at android.content.ContentResolver.takePersistableUriPermission(ContentResolver.java:1703)\n05-08 14:17:40.850 2728-2813/com.example.app W/System.err:     at com.example.app.AlbumCreator$BitmapWorkerTask.decodeSampledBitmapFromResource(AlbumCreator.java:395)\n05-08 14:17:40.850 2728-2813/com.example.app W/System.err:     at com.example.app.AlbumCreator$BitmapWorkerTask.doInBackground(AlbumCreator.java:343)\n05-08 14:17:40.850 2728-2813/com.example.app W/System.err:     at com.example.app.AlbumCreator$BitmapWorkerTask.doInBackground(AlbumCreator.java:329)\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果我在活动结果中使用 BitmapFactory.decodeFileDescriptor 从 ParcelFileDescriptor 加载位图,则不会收到此错误。因此,据我所知,AsyncTask 是具有不同权限的不同用户。有人知道如何为 AsyncTask 分配持久权限吗?I\xe2\x80\x99d 而不是在 UI 线程上加载位图。

\n\n

这是我的清单:

\n\n
<?xml version="1.0" encoding="utf-8"?>\n<manifest xmlns:android="http://schemas.android.com/apk/res/android"\n    package="com.example.app">\n    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>\n    <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />\n    <application\n        android:allowBackup="true"\n        android:icon="@mipmap/ic_launcher"\n        android:label="@string/app_name"\n        android:theme="@style/AppTheme">\n        <activity\n            android:name=".AlbumCreator"\n            android:label="@string/app_name">\n            <intent-filter>\n                <action android:name="android.intent.action.MAIN" />\n                <category android:name="android.intent.category.LAUNCHER" />\n            </intent-filter>\n        </activity>\n        <!--\n             ATTENTION: This was auto-generated to add Google Play services to your project for\n             App Indexing.  See https://g.co/AppIndexing/AndroidStudio for more information.\n        -->\n        <meta-data\n            android:name="com.google.android.gms.version"\n            android:value="@integer/google_play_services_version" />\n        <activity\n            android:name=".AlbumEditor"\n            android:label="@string/title_activity_album_editor"\n            android:parentActivityName=".AlbumCreator">\n            <meta-data\n                android:name="android.support.PARENT_ACTIVITY"\n                android:value="com.example.app.AlbumCreator" />\n        </activity>\n    </application>\n</manifest>\n
Run Code Online (Sandbox Code Playgroud)\n

Lar*_*rry 5

我解决了我自己的问题。如果您查看我的代码,您会发现我使用了intent.getData()。然后我坚持使用该 uri 的许可。当我保存 uri 供以后使用时,我对其进行了解码。Uri.decode(uri.toString()

编码后的 Uri:content://com.android.providers.media.documents/document/image%3A32 解码后:content://com.android.providers.media.documents/document/image:32

因此,我改为使用intent.getDataString(),然后使用Uri.parse() 为takePersistableUriPermission() 方法创建一个Uri。然后,我将意图中的初始数据字符串保存在数据库中,该数据库保留了编码的组件。