Замена для «GROUP BY» в запросе ContentResolver в Android Q (Android 10, изменения API 29) - PullRequest
1 голос
/ 10 марта 2020

Я обновляю некоторые устаревшие версии до цели Android Q, и, конечно, этот код перестает работать:

       String[] PROJECTION_BUCKET = {MediaStore.Images.ImageColumns.BUCKET_ID,
            MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
            MediaStore.Images.ImageColumns.DATE_TAKEN,
            MediaStore.Images.ImageColumns.DATA,
            "COUNT(" + MediaStore.Images.ImageColumns._ID + ") AS COUNT",
            MediaStore.Files.FileColumns.MEDIA_TYPE,
            MediaStore.MediaColumns._ID};

        String BUCKET_GROUP_BY = " 1) and " + BUCKET_WHERE.toString() + " GROUP BY 1,(2";

        cur = context.getContentResolver().query(images, PROJECTION_BUCKET,
            BUCKET_GROUP_BY, null, BUCKET_ORDER_BY);

android .database.sqlite.SQLiteException: рядом с "GROUP" : синтаксическая ошибка (код 1 SQLITE_ERROR [1])

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

Можно ли сгруппировать результаты запроса с помощью contentResolver, поскольку SQL запросы перестали работать?

(я знаю, что ImageColumns.DATA и "COUNT () AS COUNT" также устарели, но это вопрос о GROUP BY)

(есть возможность запрашивать альбомы и отдельно запрос фото, чтобы получить фото URI для обложки альбома, но я хочу избежать накладных расходов)

1 Ответ

1 голос
/ 11 марта 2020

К сожалению, Group By больше не будет работать в Android 10. И, как вы уже узнали, агрегированные функции, такие как COUNT , не будут работать.

Решение состоит в том, чего на самом деле пытаются избежать, запрашивать, выполнять итерации и получать метрики.

Для начала вы можете использовать следующий фрагмент, который разрешит сегменты (альбомы), и количество записей в каждом.

Я не добавил код для разрешения миниатюр, но это легко. Вы должны выполнить запрос для каждого идентификатора группы из всех экземпляров альбома и использовать изображение из первой записи.

public final class AlbumQuery
{
    @NonNull
    public static HashMap<String, AlbumQuery.Album> get(@NonNull final Context context)
    {
        final HashMap<String, AlbumQuery.Album> output     = new HashMap<>();
        final Uri                               contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;

        final String[] projection = {MediaStore.Images.Media.BUCKET_DISPLAY_NAME, MediaStore.Images.Media.BUCKET_ID};

        try (final Cursor cursor = context.getContentResolver().query(contentUri, projection, null, null, null))
        {
            if ((cursor != null) && (cursor.moveToFirst() == true))
            {
                final int columnBucketName = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_DISPLAY_NAME);
                final int columnBucketId   = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_ID);

                do
                {
                    final String bucketId   = cursor.getString(columnBucketId);
                    final String bucketName = cursor.getString(columnBucketName);

                    if (output.containsKey(bucketId) == false)
                    {
                        final int              count = AlbumQuery.getCount(context, contentUri, bucketId);
                        final AlbumQuery.Album album = new AlbumQuery.Album(bucketId, bucketName, count);
                        output.put(bucketId, album);
                    }

                } while (cursor.moveToNext());
            }
        }

        return output;
    }

    private static int getCount(@NonNull final Context context, @NonNull final Uri contentUri, @NonNull final String bucketId)
    {
        try (final Cursor cursor = context.getContentResolver().query(contentUri,
                null, MediaStore.Images.Media.BUCKET_ID + "=?", new String[]{bucketId}, null))
        {
            return ((cursor == null) || (cursor.moveToFirst() == false)) ? 0 : cursor.getCount();
        }
    }

    public static final class Album
    {
        @NonNull
        public final String buckedId;
        @NonNull
        public final String bucketName;
        public final int    count;

        Album(@NonNull final String bucketId, @NonNull final String bucketName, final int count)
        {
            this.buckedId = bucketId;
            this.bucketName = bucketName;
            this.count = count;
        }
    }
}
...