¿Cómo consultar a Android MediaStore Content Provider, evitando imágenes huérfanas?
Estoy tratando de proporcionar una actividad en la aplicación que muestra miniaturas de fotos en el almacenamiento de medios del dispositivo, y permitir al usuario seleccionar uno. Después de que el usuario hace un selección, la aplicación lee la imagen original de tamaño completo y hace cosas con ella.
Estoy usando el siguiente código para crear un Cursor
sobre todas las imágenes en el externo
almacenamiento:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView( R.layout.image_select );
mGridView = (GridView) findViewById( R.id.image_select_grid );
// Query for all images on external storage
String[] projection = { MediaStore.Images.Media._ID };
String selection = "";
String [] selectionArgs = null;
mImageCursor = managedQuery( MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI,
projection, selection, selectionArgs, null );
// Initialize an adapter to display images in grid
if ( mImageCursor != null ) {
mImageCursor.moveToFirst();
mAdapter = new LazyCursorAdapter(this, mImageCursor, R.drawable.image_select_default);
mGridView.setAdapter( mAdapter );
} else {
Log.i(TAG, "System media store is empty.");
}
}
Y el siguiente código para cargar la imagen en miniatura (Android 2.se muestra el código x):
// ...
// Build URI to the main image from the cursor
int imageID = cursor.getInt( cursor.getColumnIndex(MediaStore.Images.Media._ID) );
Uri uri = Uri.withAppendedPath( MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
Integer.toString(imageID) );
loadThumbnailImage( uri.toString() );
// ...
protected Bitmap loadThumbnailImage( String url ) {
// Get original image ID
int originalImageId = Integer.parseInt(url.substring(url.lastIndexOf("/") + 1, url.length()));
// Get (or create upon demand) the micro thumbnail for the original image.
return MediaStore.Images.Thumbnails.getThumbnail(mContext.getContentResolver(),
originalImageId, MediaStore.Images.Thumbnails.MICRO_KIND, null);
}
Y lo siguiente código para cargar la imagen original desde la URL una vez que el usuario hace una selección:
public Bitmap loadFullImage( Context context, Uri photoUri ) {
Cursor photoCursor = null;
try {
// Attempt to fetch asset filename for image
String[] projection = { MediaStore.Images.Media.DATA };
photoCursor = context.getContentResolver().query( photoUri,
projection, null, null, null );
if ( photoCursor != null && photoCursor.getCount() == 1 ) {
photoCursor.moveToFirst();
String photoFilePath = photoCursor.getString(
photoCursor.getColumnIndex(MediaStore.Images.Media.DATA) );
// Load image from path
return BitmapFactory.decodeFile( photoFilePath, null );
}
} finally {
if ( photoCursor != null ) {
photoCursor.close();
}
}
return null;
}
El problema que estoy viendo en algunos dispositivos Android, incluyendo mi propio teléfono personal, es que la
el cursor que obtengo de la consulta en onCreate()
contiene algunas entradas para las que falta el archivo de imagen real de tamaño completo (JPG o PNG). (En el caso de mi teléfono, las imágenes habían sido importadas y posteriormente borradas por iPhoto).
Las entradas huérfanas pueden o no tener miniaturas, dependiendo de si las miniaturas se generaron antes que el archivo multimedia real cuando se ausentó sin permiso. El resultado final es que la aplicación muestra miniaturas para imágenes que en realidad no existen.
Tengo algunas preguntas:
- ¿Hay una consulta que pueda hacer al proveedor de contenido
MediaStore
que filtrará ¿imágenes con medios faltantes en elCursor
devuelto? - ¿Hay un medio, o una API para forzar a
MediaStore
a volver a escanear, y eliminar las entradas huérfanas? En mi teléfono, monté USB y luego desmonté el externo medios de comunicación, que se supone que desencadena un nuevo análisis. Pero las entradas huérfanas permanecen. - ¿O hay algo fundamentalmente incorrecto en mi enfoque que está causando este problema?
Gracias.
2 answers
Bien, he encontrado el problema con este ejemplo de código.
En el método onCreate()
, tenía esta línea:
mImageCursor = managedQuery( MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI,
projection, selection, selectionArgs, null );
El problema aquí es que está consultando las miniaturas, en lugar de las imágenes reales. La aplicación de la cámara en los dispositivos HTC no crea miniaturas de forma predeterminada, por lo que esta consulta no devolverá imágenes que aún no tengan miniaturas calculadas.
En su lugar, consulta las imágenes reales:
mImageCursor = managedQuery( MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection, selection, selectionArgs, null );
Esto devolverá un cursor conteniendo todo las imágenes de tamaño completo en el sistema. A continuación, puede llamar a:
Bitmap bm = MediaStore.Images.Thumbnails.getThumbnail(context.getContentResolver(),
imageId, MediaStore.Images.Thumbnails.MINI_KIND, null);
Que devolverá la miniatura de tamaño mediano para la imagen de tamaño completo asociada, generándola si es necesario. Para obtener la miniatura de tamaño micro, simplemente use MediaStore.Images.Thumbnails.MICRO_KIND
en su lugar.
Esto también resolvió el problema de encontrar miniaturas que tienen referencias colgantes a las imágenes originales de tamaño completo.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-11 22:08:55
Tenga en cuenta que las cosas cambiarán pronto, el método managedQuery está obsoleto. Utilice CursorLoader en su lugar (desde el nivel de api 11).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-25 08:33:01