2010-09-09 6 views
36

Sto provando a fornire un'attività in-app che visualizza le miniature delle foto nell'archivio multimediale del dispositivoe consentire all'utente di selezionarne una. Dopo che l'utente effettua una selezione da , l'applicazione legge l'immagine originale a dimensione intera e fa le cose con esso.Come interrogare il fornitore di contenuti MediaStore Android, evitando immagini orfane?

Sto utilizzando il seguente codice per creare un Cursor su tutte le immagini sul esterno stoccaggio:

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."); 
    } 
} 

E il seguente codice per caricare l'immagine in miniatura (è mostrato il codice 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); 
} 

E il codice seguente per caricare l'immagine originale dall'URL una volta che l'utente effettua una selezione:

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

Il problema riscontrato su alcuni dispositivi Android, incluso il mio telefono personale, è che il cursore che ottengo dalla query in onCreate() contiene alcune voci per le quali il file immagine a grandezza originale (JPG o PNG) manca. (Nel caso del mio telefono, le immagini sono state importate e successivamente cancellate da iPhoto).

Le voci orfane possono o non possono avere miniature, a seconda se le miniature sono generate prima del file multimediale effettivo quando AWOL. Il risultato finale è che l'app visualizza miniature per immagini che in realtà non esistono.

ho alcune domande:

  1. C'è una domanda che posso fare per il fornitore di contenuti MediaStore che filtrare le immagini con i media mancante nel tornato Cursor?
  2. Esiste un mezzo o un'API per forzare la scansione di MediaStore ed eliminare le voci orfane? Sul mio telefono, ho montato su USB quindi smontato il supporto esterno, che dovrebbe attivare una nuova scansione. Ma le voci orfane rimangono.
  3. Oppure c'è qualcosa di fondamentalmente sbagliato nel mio approccio che sta causando questo problema?

Grazie.

risposta

60

OK, ho trovato il problema con questo esempio di codice.

Nel metodo onCreate(), ho avuto questa linea:

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

Il problema qui è che è l'esecuzione di query per le miniature, piuttosto che le immagini reali. L'app della fotocamera sui dispositivi HTC non crea miniature per impostazione predefinita e pertanto questa query non restituirà le immagini che non hanno già calcolato le miniature.

Invece, query per le immagini reali stessi:

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

Ciò restituirà un cursore che contiene tutte le immagini di dimensioni del sistema.È quindi possibile chiamare:

Bitmap bm = MediaStore.Images.Thumbnails.getThumbnail(context.getContentResolver(), 
     imageId, MediaStore.Images.Thumbnails.MINI_KIND, null); 

che restituirà la miniatura di medie dimensioni per l'immagine a dimensione intera associata, generandola se necessario. Per ottenere la miniatura di dimensioni ridotte, usa invece MediaStore.Images.Thumbnails.MICRO_KIND.

Questo ha risolto anche il problema di trovare le anteprime che presentano riferimenti ciondoli alle immagini originali di dimensioni standard.

7

Si prega di notare che le cose cambieranno presto, il metodo gestitoQuery è deprecato. Usa invece CursorLoader (dal livello API 11).