2010-09-09 10 views
36

Próbuję udostępnić w aplikacji aktywność, która wyświetla miniatury zdjęć w magazynie mediów urządzenia i umożliwia użytkownikowi jej wybór. Po wybraniu przez użytkownika wyboru aplikacja odczytuje oryginalny obraz w pełnym rozmiarze i robi rzeczy z nim.Jak zapytać dostawcę zawartości Android MediaStore, unikając osieroconych obrazów?

Używam następujący kod do tworzenia Cursor nad wszystkich obrazów na zewnętrznym przechowywania:

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

i następujący kod, aby załadować obraz miniatury (Android 2.x kod jest pokazany) :

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

i następujący kod do załadowania obrazu z oryginalnego adresu URL, gdy użytkownik dokonuje wyboru:

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

Problem, który widzę na niektórych urządzeniach z Androidem, w tym w moim telefonie osobistym, polega na tym, że kursor , który otrzymuję z zapytania w onCreate(), zawiera kilka pozycji, dla których faktycznie pełnowymiarowy plik obrazu (JPG lub PNG) brakuje. (W przypadku mojego telefonu obrazy zostały zaimportowane, a następnie usunięte przez iPhoto).

Osierocone wpisy mogą mieć lub nie miniatury, w zależności od tego, czy miniatury zostały wygenerowane przed rzeczywistym plikiem multimedialnym, gdy AWOL. W rezultacie aplikacja wyświetla miniatury obrazów, które w rzeczywistości nie istnieją.

mam kilka pytań:

  1. Czy istnieje kwerenda mogę zrobić, aby dostawcy treści MediaStore że będzie odfiltrować zdjęć z brakujących mediów w zwróconym Cursor?
  2. Czy istnieje środek lub interfejs API, który zmusza skaner do przetestowania, i eliminuje pozycje osierocone? Na moim telefonie zamontowałem USB, a następnie odmontowałem zewnętrzne nośniki, które mają wywołać ponowne skanowanie. Ale pozycje sieroce pozostają.
  3. Czy jest coś fundamentalnie nie tak z moim podejściem, które powoduje ten problem?

Dzięki.

Odpowiedz

60

Okej, znalazłem problem z tym przykładem kodu.

W metodzie onCreate(), miałem ten wiersz:

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

Tutaj problemem jest to, że tworzenie kwerend dla miniaturek, zamiast rzeczywistych obrazów. Aplikacja aparatu na urządzeniach HTC domyślnie nie tworzy miniatur, więc to zapytanie nie zwróci obrazów, które nie zostały jeszcze obliczone miniaturami.

Zamiast zapytanie do rzeczywistych samych obrazów:

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

ten powróci kursor zawierającą wszystkie pełnowymiarowe obrazów w systemie.Następnie można nazwać:

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

który powróci miniaturę średnich dla obrazu powiązanego pełnowymiarowego, generując w razie potrzeby. Aby uzyskać miniaturę o miniaturowym rozmiarze, użyj zamiast tego MediaStore.Images.Thumbnails.MICRO_KIND.

Rozwiązało to również problem ze znajdowaniem miniatur, które mają wiszące odniesienia do oryginalnych pełnowymiarowych obrazów.

7

Należy pamiętać, że sytuacja wkrótce się zmieni, metoda managedQuery jest przestarzała. Zamiast tego użyj CursorLoader (od poziomu interfejsu API 11).

Powiązane problemy