Объединение курсоров и сортировка

Я пишу приложение "галерейного типа" для Android. В «основном действии» у меня есть GridView, который я хочу загрузить/заполнить миниатюрами фотографий на устройстве. Итак, я написал ContentProvider, где метод запроса возвращает курсор из MediaStore.Media.Thumbnails.

Однако я также хочу отобразить некоторые метаданные из MediaStore.Media.Images. Чтобы сделать это, я использовал CursorJoiner для соединения c_thumbs и c_images по ID. Единственная проблема заключается в том, что CursorJoiner требует, чтобы входные курсоры уже были отсортированы (упорядочены) по ключу соединения (ID) в порядке возрастания. Я хочу, чтобы самые новые фотографии были сверху, но есть ли способ отсортировать существующий (уже загруженный) курсор?

В качестве альтернативы CursorJoiner, может быть, я мог бы выполнить объединение в SQL? Можно ли объединить MediaStore.Images.Media и MediaStore.Images.Thumbnails в одном запросе (и как это будет работать)?

Очевидно, это невозможно

       // split projection into MediaStore and MediaStore.Thumbs parts
        ArrayList<String> MS_proj = new ArrayList<>();
        ArrayList<String> MS_proj_thumbs = new ArrayList<>();
        for (String f : projection) {
            if (PhotoContract.ThumbEntry.COL_TYPES.get(f).equals(PhotoContract.TARGET_MEDIASTORE)) {
                MS_proj.add(f);
            } else {
                MS_proj_thumbs.add(f);
            }
        }

        String[] MS_proj_thumbs_array = new String[MS_proj_thumbs.size()];
        MS_proj_thumbs_array = MS_proj_thumbs.toArray(MS_proj_thumbs_array);

        // add _ID column to Images.Media projection, for use in JOIN
        MS_proj.add("_ID");
        String[] MS_proj_array = new String[MS_proj.size()];
        MS_proj_array = MS_proj.toArray(MS_proj_array);

        Uri baseUri;

        // first, get cursor from MediaStore.Images.Thumbnails containing all thumbnails
        baseUri = MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI;
        Log.v("TEST", "Thumb: order by " + PhotoContract.ThumbEntry.COLUMN_DATE);
        Cursor c_thumbs = getContext().getContentResolver().query(baseUri, MS_proj_thumbs_array, null, null, PhotoContract.ThumbEntry.COLUMN_IMAGE_ID);
        if (c_thumbs == null || !c_thumbs.moveToFirst()) {
            Log.v("TEST", "MediaStore.Thumbnails cursor contains no data...");
            return null;
        }

        // then, get cursor from MediaStore.Images.Media (for TITLE and DESCRIPTION etc)
        // add _ID column to query
        baseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        Cursor c_images = getContext().getContentResolver().query(baseUri, MS_proj_array, null, null, PhotoContract.ThumbEntry.COLUMN_IMAGE_PK);
        if (c_images == null || !c_images.moveToFirst()) {
            Log.v("TEST", "MediaStore.Images cursor contains no data...");
            return null;
        }

        // join these and return
        // the join is on images._ID = thumbnails.IMAGE_ID
        CursorJoiner joiner = new CursorJoiner(
                c_thumbs, new String[] { PhotoContract.ThumbEntry.COLUMN_IMAGE_ID },
                c_images, new String[] { PhotoContract.ThumbEntry.COLUMN_IMAGE_PK }
        );

        MatrixCursor retCursor = new MatrixCursor(projection);

        /*
        Does a join on two cursors using the specified columns.
        The cursors must already be sorted on each of the specified columns in ascending order.
        This joiner only supports the case where the tuple of key column values is unique.
        */
        for (CursorJoiner.Result joinerResult : joiner) {
            switch (joinerResult) {
                case LEFT:
                    // handle case where a row in cursorA is unique
                    break;
                case RIGHT:
                    // handle case where a row in cursorB is unique
                    break;
                case BOTH:

                    // handle case where a row with the same key is in both cursors
                    retCursor.addRow(new Object[]{
                            c_thumbs.getLong(0),  // ID
                            c_thumbs.getString(1), // data
                            c_thumbs.getLong(2), // image id
                            c_images.getString(0), // title
                            c_images.getString(1),  // desc
                            c_images.getLong(2)  // date
                    });
                    break;
            }
        }


        // https://stackoverflow.com/questions/12065606/getcontentresolver-query-cause-cursorwrapperinner-warning
        c_thumbs.close();
        c_images.close();

        return retCursor;

person joakimk    schedule 20.07.2015    source источник


Ответы (1)


Ха, кажется, можно «обмануть» Android, разрешив CursorJoiner с сортировкой по убыванию, просто упорядочив по ID*(-1) (по возрастанию):

Cursor c_thumbs = getContext().getContentResolver().query(
                baseUri, 
                MS_proj_thumbs_array, null, null, 
                "(" + PhotoContract.ThumbEntry.COLUMN_IMAGE_ID + "*(-1))"  // NB!
       );

Так что это решает мою проблему; самые новые изображения сверху!

Полный ответ см. здесь: Запрос MediaStore: объединение миниатюр и изображений (по идентификатору)

person joakimk    schedule 18.09.2015