Android: как запросить список имен сегментов

Я хочу получить только название ведра (Альбомы). Например. Камера, загрузка и т. д., но не список камер, загрузка и т. д. со всех фотографий, так как мне получить по одной строке для каждого имени корзины?

Что я имею в виду, как и в приложении «Галерея», у вас сначала есть альбомы, например. Камера. Когда вы нажимаете на него, он показывает все фотографии камеры.

Я могу запросить фотографии в фотопленке с предложением запроса Where. Но что, если мне нужно только название каждого из названий альбомов, а не фотографии, можно ли это запросить? Если я запросю все фотографии и возьму только одну строку для каждого набора фотографий, это займет много времени.

Пожалуйста помоги


person LittleFunny    schedule 19.07.2012    source источник


Ответы (5)


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

(Обратите внимание, что повторение сегмента удаляется методом группировки и порядка)

    // which image properties are we querying
    String[] PROJECTION_BUCKET = {
            ImageColumns.BUCKET_ID,
            ImageColumns.BUCKET_DISPLAY_NAME,
            ImageColumns.DATE_TAKEN,
            ImageColumns.DATA};
    // We want to order the albums by reverse chronological order. We abuse the
    // "WHERE" parameter to insert a "GROUP BY" clause into the SQL statement.
    // The template for "WHERE" parameter is like:
    //    SELECT ... FROM ... WHERE (%s)
    // and we make it look like:
    //    SELECT ... FROM ... WHERE (1) GROUP BY 1,(2)
    // The "(1)" means true. The "1,(2)" means the first two columns specified
    // after SELECT. Note that because there is a ")" in the template, we use
    // "(2" to match it.
    String BUCKET_GROUP_BY =
            "1) GROUP BY 1,(2";
    String BUCKET_ORDER_BY = "MAX(datetaken) DESC";

    // Get the base URI for the People table in the Contacts content provider.
    Uri images = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;

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

    Log.i("ListingImages"," query count=" + cur.getCount());

    if (cur.moveToFirst()) {
        String bucket;
        String date;
        String data;
        int bucketColumn = cur.getColumnIndex(
                MediaStore.Images.Media.BUCKET_DISPLAY_NAME);

        int dateColumn = cur.getColumnIndex(
                MediaStore.Images.Media.DATE_TAKEN);
        int dataColumn = cur.getColumnIndex(
                MediaStore.Images.Media.DATA);

        do {
            // Get the field values
            bucket = cur.getString(bucketColumn);
            date = cur.getString(dateColumn);
            data = cur.getString(dataColumn);

            // Do something with the values.
            Log.i("ListingImages", " bucket=" + bucket 
                    + "  date_taken=" + date
                    + "  _data=" + data);
        } while (cur.moveToNext());
    }
person Thuong    schedule 10.12.2013
comment
Как сделать так, чтобы в ведре не было фотографий? - person Krunal Shah; 27.05.2015
comment
Не знаю, но я получаю повторяющиеся записи на 5.0, есть идеи? - person ingsaurabh; 15.11.2015
comment
@Krunal Shah Я бы попытался запустить еще один запрос для каждого сегмента, который фильтрует BUCKET_ID в параметре where. - person stwienert; 16.05.2016
comment
в случае запроса всех video альбомов измените uri на: uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI - person Nilesh Deokar; 04.03.2019
comment
The "1,(2)" means the group by first two columns. Которые ImageColumns.BUCKET_ID, ImageColumns.BUCKET_DISPLAY_NAME указаны в PROJECTION_BUCKET - person Nilesh Deokar; 06.03.2019
comment
лучшим способом написания предложения GROUP BY было бы: val bucketGroupBy = "1) GROUP BY ${ImageColumns.BUCKET_ID}, (${ImageColumns.BUCKET_DISPLAY_NAME}" . Почему мы используем Group by 1 и Group by 1,2,3 в SQL-запросе? - person Nilesh Deokar; 06.03.2019
comment
этот код не работает с версией выше android pie (android 10), он показывает синтаксическую ошибку в 1) GROUP BY 1, (ключевое слово 2. - person Bhavik Nathani; 07.11.2019
comment
Как написал @BhavikNathani, это не работает в Android 10. Кто-нибудь знает, как это заменить? - person grebulon; 26.12.2019

Вот. меня устраивает:

Uri images = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
    String[] projection = new String[]{   
            MediaStore.Images.Media.BUCKET_ID,
            MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
            MediaStore.Images.Media.DATE_TAKEN,
            MediaStore.Images.Media.DATA
    };

    String BUCKET_ORDER_BY = MediaStore.Images.Media.DATE_MODIFIED + " DESC";
    String BUCKET_GROUP_BY = "1) GROUP BY 1,(2";
    Cursor imagecursor = managedQuery(images,
            projection, // Which columns to return
            BUCKET_GROUP_BY,       // Which rows to return (all rows)
            null,       // Selection arguments (none)
            BUCKET_ORDER_BY        // Ordering
            );

    this.imageUrls = new ArrayList<String>();
    this.imageBuckets  = new ArrayList<String>();
    for (int i = 0; i < imagecursor.getCount(); i++)
    {
        imagecursor.moveToPosition(i);
        int bucketColumnIndex = imagecursor.getColumnIndex(MediaStore.Images.Media.BUCKET_DISPLAY_NAME);
        String bucketDisplayName = imagecursor.getString(bucketColumnIndex);
        imageBuckets.add(bucketDisplayName);
        int dataColumnIndex = imagecursor.getColumnIndex(MediaStore.Images.Media.DATA);
        imageUrls.add(imagecursor.getString(dataColumnIndex));

    }

imageBuckets Arraylist содержит названия альбомов

imageUrls Arraylist содержит путь к последнему измененному изображению альбома, которое вы можете использовать в качестве эскиза.

person farhad.kargaran    schedule 30.09.2014
comment
Как сделать так, чтобы в ведре не было фотографий? - person Krunal Shah; 27.05.2015
comment
лучшим способом написания предложения GROUP BY было бы: val bucketGroupBy = "1) GROUP BY ${ImageColumns.BUCKET_ID}, (${ImageColumns.BUCKET_DISPLAY_NAME}" . Почему мы используем Group by 1 и Group by 1,2,3 в SQL-запросе? - person Nilesh Deokar; 06.03.2019

Используйте следующую функцию для получения альбомов видео или изображений:

   /*
    *
    *   Author : @nieldeokar
    *   mediaType could be one of
    *
    *   public static final int MEDIA_TYPE_IMAGE = 1;
    *
    *   public static final int MEDIA_TYPE_VIDEO = 3;
    *
    *   from android.provider.MediaStore class
    *
    */
fun getAlbumList(mediaType: Int, contentResolver: ContentResolver) {
    val countColumnName = "count"
    var contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
    if (mediaType == MEDIA_TYPE_VIDEO) {
        contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
    }

    val projection = arrayOf(ImageColumns.BUCKET_ID, ImageColumns.BUCKET_DISPLAY_NAME, ImageColumns.DATE_TAKEN, ImageColumns.DATA)
    val bucketGroupBy = "1) GROUP BY ${ImageColumns.BUCKET_ID}, (${ImageColumns.BUCKET_DISPLAY_NAME}"
    val bucketOrderBy = MediaStore.Images.Media.DATE_MODIFIED + " DESC"

    val cursor = contentResolver.query(contentUri, projection, bucketGroupBy, null, bucketOrderBy)


    if (cursor != null) {
        while (cursor.moveToNext()) {
            val bucketId = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.BUCKET_ID))
            val name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME))
            val path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA)) // Thumb image path

            val selection = MediaStore.Images.Media.BUCKET_ID + "='" + bucketId + "'"

            val countCursor = contentResolver.query(contentUri, arrayOf( "count(" + MediaStore.Images.ImageColumns._ID + ")"), selection, null, null)

            var count = 0
            if (countCursor != null) {
                countCursor.moveToFirst()
                count = countCursor.getInt(0)
                countCursor.close()
            }

            Log.d("AlbumScanner", "bucketId : $bucketId | name : $name | count : $count | path : $path")
        }
        cursor.close()

    }

}

Это формирует оператор SQL как:

SELECT bucket_id, bucket_display_name, datetaken, _data FROM images WHERE (1) GROUP BY bucket_id,(bucket_display_name) ORDER BY date_modified DESC

ОБНОВЛЕНИЕ: Как отметил @PerracoLabs, этот код необходимо улучшить для ориентации на Android Q.

person Nilesh Deokar    schedule 06.03.2019
comment
Учтите, что старый трюк с группировкой 1) GROUP BY больше не работает в Android Q - person PerracoLabs; 19.03.2019
comment
Я все еще тестирую его на Q. Групповой запрос работает, но count(*) AS count не работает. @PerracoLabs ваш вклад был бы очень полезен. - person Nilesh Deokar; 20.03.2019
comment
Вы настроили свой Gradle на Q? Тест проводился в эмуляторе. При выполнении запроса к MediaStore с использованием ContentResolver я обнаружил, что платформа автоматически включает в начале сгенерированного запроса в условие Where следующую строку: (IS_TRASHED=0) AND (IS_PENDING=0). Они добавляются независимо от того, что вы делаете, и проблема в том, что они делают скобку 1) GROUP несбалансированной и, следовательно, создают недопустимый синтаксический запрос. - person PerracoLabs; 20.03.2019
comment
Кроме того, проверяя ваш код, я вижу, что вы используете поле DATA. К сожалению, это также устарело: developer.android.com/reference /андроид/провайдер/ - person PerracoLabs; 20.03.2019
comment
Спасибо, что указали на исправления. На данный момент я обновил сообщение с предупреждением для Android Q. Я бы протестировал цель Q, а затем как можно скорее улучшу код. - person Nilesh Deokar; 21.03.2019
comment
Любые решения для 1) GROUP BY в Android Q? - person Mateen Chaudhry; 30.06.2019
comment
Обратите внимание, необходимо протестировать запросы с целевым SDK 29 + Android Q. - person Efi G; 23.03.2020

Вы можете запросить MediaStore.Images.Media.BUCKET_DISPLAY_NAME для этого. Питер Кнего прислал хороший пример. Это хороший пример, и вы можете обновите его, используя query() из объекта ContentResolver, а не manageQuery(), который устарел.

// which image properties are we querying
String[] projection = new String[]{
        MediaStore.Images.Media._ID,
        MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
        MediaStore.Images.Media.DATE_TAKEN
};

// Get the base URI for the People table in the Contacts content provider.
Uri images = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;

// Make the query.
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(images,
        projection, // Which columns to return
        "",         // Which rows to return (all rows)
        null,       // Selection arguments (none)
        ""          // Ordering
        );

Log.i("ListingImages"," query count="+cur.getCount());

if (cur.moveToFirst()) {
    String bucket;
    String date;
    int bucketColumn = cur.getColumnIndex(
        MediaStore.Images.Media.BUCKET_DISPLAY_NAME);

    int dateColumn = cur.getColumnIndex(
        MediaStore.Images.Media.DATE_TAKEN);

    do {
        // Get the field values
        bucket = cur.getString(bucketColumn);
        date = cur.getString(dateColumn);

        // Do something with the values.
        Log.i("ListingImages", " bucket=" + bucket 
               + "  date_taken=" + date);
    } while (cur.moveToNext());

}
person Pedro Alves    schedule 09.08.2012
comment
Хорошо, но я хочу запрашивать только уникальное отображаемое имя корзины вместо списка повторяющихся отображаемых имен корзины. Например. Я хочу что-то вроде альбома Camera and Competition. Но для вашего примера кода он будет отображать что-то вроде «Камера», «Камера», «Камера», «Конкурс», «Конкурс» и т. Д. - person LittleFunny; 15.08.2012
comment
Да! Я решил это, добавив каждый элемент в HashMap в качестве ключа. Это немного раздражает, но это работает. - person Pedro Alves; 18.08.2012
comment
Все еще не решает проблему правильно — у вас могут быть две уникальные папки с одинаковым отображаемым именем и разными фотографиями. BUCKET_IT — это то, что должно быть ключом для хеша, а не отображаемым именем. - person jt-gilkeson; 24.05.2017

Сделайте проекцию в запросе, как показано ниже:

String bucketProjection[] = {"Distinct "+ MediaStore.Images.Media.BUCKET_DISPLAY_NAME};
person kiran    schedule 08.03.2017
comment
Отображаемое имя не является уникальным идентификатором (у вас могут быть две разные папки с одинаковым именем) — уникальный идентификатор BUCKET_ID. Если вам нужен список уникальных папок, вы рассматриваете две папки с одинаковыми именами как одну, поскольку в двух корзинах с одинаковыми именами есть разные изображения. - person jt-gilkeson; 24.05.2017