Запрос всех изображений с телефона работает на API 18, но не на API 30

avatar
Omar Shawky
8 августа 2021 в 21:54
186
1
0

Решено повторным запросом разрешений во время выполнения

Недавно я работал над своим приложением и хотел запросить все изображения на своем телефоне, поэтому я прочитал Руководство для разработчиков Android

И мог нормально получить все изображения на телефоне с API 18, но когда я попробовал это на телефоне с 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> 
Источник
CommonsWare
8 августа 2021 в 21:55
0

Запрашивали ли вы READ_EXTERNAL_STORAGE во время выполнения в дополнение к записи в манифесте?

Omar Shawky
8 августа 2021 в 22:01
0

да, в качестве одной из моих попыток решить проблему я попытался проверить, есть ли у меня разрешение с условием if, но ничего не появилось, чтобы снова запросить разрешения, если у меня их нет. if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},1); }

Omar Shawky
8 августа 2021 в 22:14
0

да, вы правы, это была проблема с разрешениями, в первый раз, когда я попробовал, ничего не выскочило, чтобы запросить разрешения, поэтому я думал, что все в порядке, но теперь я попробовал это буквально перед тем, как сделать запрос, и появилось сообщение с запросом на разрешить приложению читать хранилище, что было очень странно :\

Omar Shawky
8 августа 2021 в 22:16
0

разве наличие разрешения на использование в манифесте не должно гарантировать, что приложение имеет необходимые разрешения !!?

CommonsWare
8 августа 2021 в 22:20
2

«Не должно ли наличие разрешения на использование в манифесте гарантировать, что приложение имеет необходимые разрешения !!?» -- не начиная с Android 6.0, шесть лет назад.

Noah
8 августа 2021 в 22:33
0

@OmarShawky запрашивает разрешение READ_EXTERNAL_STORAGE? Потому что я сейчас сталкиваюсь с этой же проблемой.

Noah
8 августа 2021 в 22:40
0

У меня есть разрешение READ_EXTERNAL_STORAGE в манифесте, и я запросил его во время выполнения, но он все равно дает сбой. Мое приложение работает на API < 30

Omar Shawky
9 августа 2021 в 19:55
0

@EbenmeluNoah, Уилл, в первый раз, когда я попробовал это, как я уже сказал, он не показывал никаких всплывающих сообщений, поэтому я думал, что все в порядке, но теперь он показывает его нормально, поэтому я не знаю, что именно изменилось за это время и теперь, может быть, я использовал устаревший метод во фрагменте для запроса разрешений, но теперь я переключился на то, как я думаю, что они обрабатывают его в соответствии с разработчиками Android, в любом случае я могу поделиться в своем посте как отредактировать код, который я использую сейчас, чтобы проверьте наличие разрешений во фрагменте, не используя устаревший метод (который может быть в случае вашей проблемы), если это может вам помочь :thonk:

Ответы (1)

avatar
Omar Shawky
13 сентября 2021 в 00:15
0

Решение заключалось в повторном запросе разрешений во время выполнения, поэтому мой код сработал для меня после прочтения следующего руководства Запрашивать разрешения приложения во время выполнения:

  1. Сначала инициализируйте ActivityResultLauncher и зарегистрируйте его как результат действия, который должен быть до {initialization, 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();
    }