查询来自 phone 的所有图像适用于 api 18 但不适用于 api 30

Query all images from phone works on api 18 but not on api 30

运行时再次请求权限解决

最近我在开发我的应用程序,我想查询我 phone 上的所有图像,所以我阅读了 Android developers tutorial

并且可以在 phone 和 api 18 上正常检索所有图像,但是当我在 phone 和 api 30 上尝试它时它没有检索即使是一张图片,尽管它是同一个应用程序。

我什至后来尝试了他们的代码来获取视频,但它也没有用,所以我现在不知道缺少什么,任何建议将不胜感激:(

我的查询代码:

public ArrayList<CustomPhoto> getPhotosFromExternalStorage() {
        Uri collection;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            collection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);
        } else {
            collection = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        }

        String[] projection = new String[]{
                MediaStore.Images.Media._ID,
                MediaStore.Images.Media.DISPLAY_NAME,
                MediaStore.Images.Media.BUCKET_DISPLAY_NAME
        };
        String sortOrder = MediaStore.Images.Media.DATE_ADDED + " ASC";
        ArrayList<CustomPhoto> queryResult = new ArrayList<>();
        try (Cursor cursor = context.getApplicationContext().getContentResolver().query(
                collection,
                projection,
                null,
                null,
                sortOrder
        )) {
            int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID);
            int nameColumn =
                    cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME);
            int bucketColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_DISPLAY_NAME);
            Log.e("retrieved = " , Integer.valueOf(cursor.getCount()).toString());

            while (cursor.moveToNext()) {
                // Get values of columns for a given video.
                long id = cursor.getLong(idColumn);
                String name = cursor.getString(nameColumn);
                String bucket_display_name = cursor.getString(bucketColumn);
                Uri contentUri = ContentUris.withAppendedId(
                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);
                Log.e("uri" , bucket_display_name);
                queryResult.add(new CustomPhoto(contentUri.toString(),bucket_display_name, name));

            }
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
        return queryResult;
    }

我的清单:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.pretest">
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
        />
    <!-- android:hardwareAccelerated="false"
        android:largeHeap="true"-->
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.FacebookTest">
        <meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/>
        <meta-data android:name="com.facebook.sdk.ClientToken" android:value="@string/facebook_client_token"/>
        <activity android:name="com.facebook.FacebookActivity"
            android:configChanges=
                "keyboard|keyboardHidden|screenLayout|screenSize|orientation"
            android:label="@string/app_name" />
        <activity
            android:name="com.facebook.CustomTabActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="@string/fb_login_protocol_scheme" />
            </intent-filter>
        </activity>

        <activity
            android:name="com.example.pretest.MainActivity"
            android:label="@string/app_name"
            android:theme="@style/Theme.FacebookTest.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest> 

解决方案是在 运行 时再次请求权限,这样我的代码在阅读以下教程后对我有用 Request app permissions at runtime:

  1. 首先初始化一个ActivityResultLauncher并将其注册为activity结果,该结果必须在{初始化,onAttach(),或onCreate()}片段之前创建方法,所以唯一的方法是将其初始化为全局片段变量

  2. 然后当我需要开始从外部存储查询图像时,我使用我之前初始化的ActivityResultLauncher来启动所需权限的请求。

  3. 如果授予权限,回调应该 运行 负责获取照片的方法,否则(暂时)它会显示提示消息,告诉用户为什么他不能继续他的操作

我的片段代码:

public class myFragment extends Fragment {
ActivityResultLauncher<String> requestPermissionLauncher =
            registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
                if (isGranted) goFetchPhotos();
                else
                    Toast.makeText(getContext(), "Can't continue without the required permissions", Toast.LENGTH_LONG).show();
            });
//this function runs when something happens in my app
public void getNecessaryPermissionsAndFetchPhotos() {
        if (ActivityCompat.checkSelfPermission(getContext(),
                Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
     requestPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE);
        }else goFetchPhotos();
    }