连接游标和排序

Joining cursors and sorting

我正在为 Android 编写一个 "gallery-type" 应用程序。在 "master activity" 中,我有一个 GridView,我想 load/fill 使用设备上照片的缩略图。所以我写了一个 ContentProvider,其中查询方法 returns 来自 MediaStore.Media.Thumbnails.

的游标

不过,我还想显示一些来自 MediaStore.Media.Images 的元数据。为了做到这一点,我最终使用 CursorJoiner 在 ID 上加入 c_thumbs 和 c_images。唯一的问题是 CursorJoiner 要求输入游标已经在连接键 (ID) 上按升序排序(排序)。我想要的是最新的照片在上面,但是有没有办法对现有的(已经加载的)光标进行排序?

Alternatively to CursorJoiner, maybe I could do the join in SQL? Is it possible to join MediaStore.Images.Media and MediaStore.Images.Thumbnails in one query (and how would that work)?

Apparently, that's not possible

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


        // 
        c_thumbs.close();
        c_images.close();

        return retCursor;

哈,似乎可以 "trick" Android 允许 CursorJoiner 降序 通过简单地按 ID*(-1)(升序)排序:

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

这样就解决了我的问题;最新图片在最上面!

在此处查看完整答案: