如何查询 Android MediaStore Content Provider,避免孤立图像?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3680357/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 11:19:35  来源:igfitidea点击:

How to query Android MediaStore Content Provider, avoiding orphaned images?

androidimagemediaandroid-contentprovider

提问by mportuesisf

I'm trying to provide an in-app Activity which displays thumbnails of photos in the device's media store, and allow the user to select one. After the user makes a selection, the application reads the original full-size image and does things with it.

我正在尝试提供一个应用内活动,它显示设备媒体商店中照片的缩略图,并允许用户选择一个。用户做出选择后,应用程序会读取原始全尺寸图像并对其进行处理。

I'm using the following code to create a Cursorover all the images on the external storage:

我正在使用以下代码Cursor在外部存储上创建所有图像:

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

And the following code to load the thumbnail image (Android 2.x code is shown):

以及以下用于加载缩略图的代码(显示的是 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);
}

And the following code to load the original image from the URL once the user makes a selection:

以下代码用于在用户进行选择后从 URL 加载原始图像:

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

The problem I'm seeing on some Android devices, including my own personal phone, is that the cursor I get from the query in onCreate()contains a few entries for which the actual full-sized image file (JPG or PNG) is missing. (In the case of my phone, the images had been imported and subsequently erased by iPhoto).

我在某些 Android 设备(包括我自己的个人手机)上看到的问题是,我从查询中获得的光标onCreate()包含一些缺少实际全尺寸图像文件(JPG 或 PNG)的条目。(就我的手机而言,图像已被导入并随后被 iPhoto 删除)。

The orphaned entries may or may not have thumbnails, depending upon whether thumbnails where generated before the actual media file when AWOL. The end result is that the app displays thumbnails for images that don't actually exist.

孤立条目可能有也可能没有缩略图,这取决于缩略图是否在 AWOL 时在实际媒体文件之前生成。最终结果是该应用程序显示实际不存在的图像的缩略图。

I have a few questions:

我有几个问题:

  1. Is there a query I can make to the MediaStorecontent provider that will filter out images with missing media in the returned Cursor?
  2. Is there a means, or an API to force the MediaStoreto rescan, and eliminate the orphan entries? On my phone, I USB-mounted then unmounted the external media, which is supposed to trigger a rescan. But the orphan entries remain.
  3. Or is there something fundamentally wrong with my approach that's causing this problem?
  1. 我是否可以向MediaStore内容提供者进行查询,以过滤掉返回的缺少媒体的图像Cursor
  2. 有没有办法或 API 来强制MediaStore重新扫描并消除孤立条目?在我的手机上,我安装了 USB,然后卸载了外部媒体,这应该会触发重新扫描。但是孤儿条目仍然存在。
  3. 或者我的方法有什么根本性的错误导致了这个问题?

Thanks.

谢谢。

回答by mportuesisf

Okay, I've found the problem with this code sample.

好的,我发现此代码示例存在问题。

In the onCreate()method, I had this line:

onCreate()方法中,我有这一行:

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

The problem here is that it's querying for the thumbnails, rather than the actual images. The camera app on HTC devices does not create thumbnails by default, and so this query will fail to return images that do not already have thumbnails calculated.

这里的问题是它查询的是缩略图,而不是实际的图像。默认情况下,HTC 设备上的相机应用程序不会创建缩略图,因此此查询将无法返回尚未计算缩略图的图像。

Instead, query for the actual images themselves:

相反,查询实际图像本身:

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

This will return a cursor containing all the full-sized images on the system. You can then call:

这将返回一个包含系统上所有全尺寸图像的光标。然后你可以调用:

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

which will return the medium-sized thumbnail for the associated full-size image, generating it if necessary. To get the micro-sized thumbnail, just use MediaStore.Images.Thumbnails.MICRO_KINDinstead.

这将返回相关全尺寸图像的中等尺寸缩略图,必要时生成它。要获得微型缩略图,只需使用即可MediaStore.Images.Thumbnails.MICRO_KIND

This also solved the problem of finding thumbnails that have dangling references to the original full-sized images.

这也解决了查找对原始全尺寸图像具有悬空引用的缩略图的问题。

回答by Tamas

Please note that things will be changing soon, managedQuery method is deprecated. Use CursorLoader instead(since api level 11).

请注意,事情很快就会改变,managedQuery 方法已被弃用。改用 CursorLoader(自 API 级别 11 起)。