2010-09-09 3 views
36

Ich versuche, eine In-App-Aktivität bereitzustellen, die Miniaturansichten von Fotos im Medienspeicher des Geräts anzeigt und dem Benutzer die Auswahl eines Mediums ermöglicht. Nachdem der Benutzer eine Auswahl getroffen hat, liest die Anwendung das ursprüngliche Bild in voller Größe und macht damit etwas.Wie wird der Android MediaStore Content Provider abgefragt, um verwaiste Bilder zu vermeiden?

ich den folgenden Code bin mit einem Cursor über alle Bilder auf dem externen Speicher zu erstellen:

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

und den folgenden Code, um das Thumbnail-Bild zu laden (Android 2.x-Code wird angezeigt) :

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

und der folgende Code, um das Originalbild aus der URL zu laden, sobald der Benutzer eine Auswahl trifft:

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

Das Problem, das ich auf einigen Android-Geräten, einschließlich meines eigenen persönlichen Telefons sehe, ist, dass der Cursor, den ich von der Abfrage in onCreate() erhalte, ein paar Einträge enthält, für die die tatsächliche Bilddatei in voller Größe (JPG oder PNG) wird vermisst. (Im Fall meines Telefons wurden die Bilder importiert und anschließend von iPhoto gelöscht).

Die verwaisten Einträge können oder können keine Miniaturansichten haben, abhängig davon, ob Miniaturbilder vor der eigentlichen Mediendatei generiert wurden, wenn AWOL. Das Ergebnis ist, dass die App Miniaturansichten für Bilder anzeigt, die nicht wirklich existieren.

Ich habe ein paar Fragen:

  1. Gibt es eine Abfrage, die ich an die MediaStore Content-Provider machen kann, die Bilder mit fehlenden Medien in den zurück Cursor herausfiltern?
  2. Gibt es eine Möglichkeit, oder eine API, die MediaStore zum erneuten Scannen erzwingen und die verwaisten Einträge zu beseitigen? Auf meinem Handy habe ich USB-gemountet und dann das externe Medium abgehängt, welches einen Rescan auslösen soll. Die verwaisten Einträge bleiben jedoch erhalten.
  3. Oder gibt es etwas grundsätzlich falsch mit meinem Ansatz, der dieses Problem verursacht?

Danke.

Antwort

60

Okay, ich habe das Problem mit diesem Codebeispiel gefunden.

Im onCreate() Methode hatte ich diese Zeile:

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

Das hier Problem ist, dass es für die Thumbnails ist die Abfrage, anstatt die tatsächlichen Bilder. Die Kamera-App auf HTC-Geräten erstellt standardmäßig keine Miniaturansichten. Daher liefert diese Abfrage keine Bilder, für die noch keine Miniaturansichten berechnet wurden.

Stattdessen Abfrage für die eigentlichen Bilder selbst:

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

Dies wird einen Cursor zurückgeben alle Bildern in voller Größe auf dem System enthält.Sie können dann anrufen:

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

die das mittelgroße Thumbnail für das zugehörige Bild in voller Größe zurückgibt und es bei Bedarf erzeugt. Um das Miniatur-Miniaturbild zu erhalten, verwenden Sie stattdessen MediaStore.Images.Thumbnails.MICRO_KIND.

Dies löste auch das Problem der Suche nach Thumbnails, bei denen Referenzen auf die Originalbilder in Originalgröße vorhanden sind.

7

Bitte beachten Sie, dass sich die Dinge in Kürze ändern werden, die Methode "managedQuery" ist veraltet. Benutze stattdessen CursorLoader (seit API Level 11).