2010-09-09 14 views
36

Estoy tratando de proporcionar una Actividad en la aplicación que muestra miniaturas de fotos en el almacén de medios del dispositivo , y permite al usuario seleccionar una. Después de que el usuario hace una selección , la aplicación lee la imagen original en tamaño completo y hace cosas con ella.Cómo consultar el proveedor de contenido Android MediaStore, evitando las imágenes huérfanas?

estoy usando el siguiente código para crear un Cursor sobre todas las imágenes en el exterior de 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 código siguiente para cargar la imagen en miniatura (se muestra el código Android 2.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 el código siguiente para cargar la imagen original de la URL una vez que el usuario realiza 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, incluido mi propio teléfono personal, es que el cursor que obtengo de la consulta en onCreate() contiene algunas entradas para las cuales el archivo de imagen de tamaño real (JPG o PNG) Está perdido. (En el caso de mi teléfono, las imágenes habían sido importadas y posteriormente borradas por iPhoto).

Las entradas huérfanas pueden tener o no miniaturas, dependiendo de si las miniaturas se generaron antes del archivo de medios real cuando están ausentes sin permiso. El resultado final es que la aplicación muestra miniaturas de imágenes que en realidad no existen.

Tengo algunas preguntas:

  1. ¿Existe una consulta que puedo hacer al proveedor de contenido MediaStore que filtrará a cabo imágenes con la falta de medios de comunicación en la Cursor vuelto?
  2. ¿Hay un medio, o una API para forzar el MediaStore para volver a analizar y eliminar las entradas huérfanas? En mi teléfono, monté con un USB y luego desmonté el medio externo, que se supone que dispara una nueva búsqueda. Pero las entradas huérfanas permanecen.
  3. ¿O hay algo fundamentalmente erróneo en mi enfoque que está causando este problema?

Gracias.

Respuesta

60

Bien, he encontrado el problema con este ejemplo de código.

En el método onCreate(), tuve esta línea:

mImageCursor = managedQuery(MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, 
          projection, selection, selectionArgs, null); 

El problema aquí es que está la consulta de las imágenes en miniatura, 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 generará imágenes que no tengan las miniaturas calculadas.

En cambio, la consulta de las propias imágenes reales:

mImageCursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 
          projection, selection, selectionArgs, null); 

Esto devolverá un cursor que contiene todas las imágenes a 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 una miniatura de tamaño micro, simplemente use MediaStore.Images.Thumbnails.MICRO_KIND.

Esto también resuelve el problema de encontrar miniaturas que tienen referencias pendientes a las imágenes a tamaño completo originales.

7

Tenga en cuenta que las cosas cambiarán pronto, el método managedQuery está en desuso. Use CursorLoader en su lugar (desde el nivel 11 de la API).

Cuestiones relacionadas