Unir cursores y ordenar

Estoy escribiendo una aplicación "tipo galería" para Android. En la "actividad maestra", tengo un GridView que quiero cargar / llenar con miniaturas de las fotos en el dispositivo. Así que escribí un ContentProvider, donde el método de consulta devuelve un cursor desde MediaStore.Media.Thumbnails.

Sin embargo, también quiero mostrar algunos metadatos de MediaStore.Media.Images. Para hacer esto, terminé usando un CursorJoiner para unir c_thumbs y c_images en ID. El único problema con esto es que CursorJoiner requiere que los cursores de entrada ya estén ordenados (ordenados) en la clave de unión (ID), en orden ascendente. Lo que quiero son las fotos más nuevas en la parte superior, pero ¿hay alguna manera de ordenar un cursor existente (ya cargado)?

Alternativamente a CursorJoiner, ¿tal vez podría hacer la unión en SQL? ¿Es posible unir MediaStore.Images.Media y MediaStore.Images.Thumbnails en una consulta (y cómo funcionaría)?

Aparentemente, eso no es posible.

       // 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;

Respuestas a la pregunta(1)

Su respuesta a la pregunta