37 votes

Comment interroger Android MediaStore Content Provider, en évitant les images orphelines?

Je suis en train d'offrir une Activité app qui affiche des vignettes de photos dans la du périphérique de stockage, et de permettre à l'utilisateur d'en choisir un. Après que l'utilisateur a fait une la sélection, l'application lit l'original de la taille de l'image et fait des choses avec elle.

J'utilise le code suivant pour créer un Cursor sur toutes les images sur l'extérieur stockage:

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

Et le code suivant pour charger l'image miniature (Android 2.x code est affiché):

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

Et le code suivant pour charger l'image d'origine à partir de l'URL une fois que l'utilisateur effectue une sélection:

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

Le problème que je vois sur certains appareils Android, y compris mon propre téléphone, c'est que l' curseur-je obtenir à partir de la requête en onCreate() contient quelques entrées pour lesquelles l'effectif complet de la taille de fichier image (JPG ou PNG) est manquant. (Dans le cas de mon téléphone, les images avaient été importés et, par la suite effacé par iPhoto).

Les orphelins entrées peuvent ou peuvent ne pas avoir les vignettes, selon que les vignettes où générés avant la réelle fichier de média lors de la AWOL. Le résultat final est que l'application affiche des vignettes pour les images qui n'existe pas réellement.

J'ai quelques questions:

  1. Est-il une requête que je peux apporter à l' MediaStore fournisseur de contenu qui filtre des images avec le manque de supports dans le retour de l' Cursor?
  2. Est-il un moyen ou une API pour forcer l' MediaStore afin de relancer l'analyse, et d'éliminer les entrées orphelines? Sur mon téléphone, j'USB-monté puis démonté le support externe, qui est censé déclencher une nouvelle analyse. Mais les entrées orphelines rester.
  3. Ou est-il quelque chose de fondamentalement mauvais dans mon approche qui est à l'origine de ce problème?

Merci.

61voto

mportuesisf Points 3792

Ok, j'ai trouvé le problème avec cet exemple de code.

Dans l' onCreate() méthode, j'ai eu cette ligne:

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

Le problème ici est que c'est l'interrogation pour les vignettes, plutôt que sur les images. L'application appareil photo sur les appareils HTC ne pas créer des vignettes par défaut, et si cette requête ne renvoie des images qui n'ont pas déjà des vignettes calculé.

Au lieu de cela, la requête de l'effectif des images elles-mêmes:

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

Cela renvoie un curseur contenant toutes les images en pleine taille sur le système. Vous pouvez ensuite appeler:

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

qui sera de retour à la moyenne de la taille d'une miniature de l'image correspondante en taille réelle, de le créer si nécessaire. Pour obtenir la taille de micro-miniature, il suffit d'utiliser MediaStore.Images.Thumbnails.MICRO_KIND à la place.

Cela a également résolu le problème de trouver des vignettes qui ont balançant des références à l'original images en pleine taille.

7voto

Tamas Points 349

S'il vous plaît noter que les choses vont changer bientôt, la méthode managedQuery est déprécié. Utilisez CursorLoader à la place (depuis api niveau 11).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X