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;