查询MediaStore:加入缩略图和图像(上ID) [英] Querying the MediaStore: Joining thumbnails and images (on ID)

查看:454
本文介绍了查询MediaStore:加入缩略图和图像(上ID)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为Android一个图片库型的应用程序。它开始作为开发Android应用在Udacity一个决赛项目,所以它的整体结构(活动,contentproviders等)应该是非常健全的,它被接受由Udacity /谷歌认证。

I'm working on a "photo gallery"-type app for Android. It started as a Final Project for the Developing Android Apps at Udacity, so it's overall structure (activities, contentproviders etc) should be very sound, and it was accepted for certification by Udacity/Google.

然而,它仍然不是100%完成,而我仍然在试图改善它。

However, it's still not 100% finished, and I'm still trying to improve on it.

我想要做的真的应该是相当直接的;设备上的所有图像(缩略图)加载到在MainActivity一个GridView,具有DetailActivity这说明原图+一些元数据(标题,大小,日期等)。

本课程要求我们写一个ContentProvider的,所以我有一个查询()函数基本上从MediaStore获取数据,并返回一个光标MainActivity的GridView控件。在我的设备,至少,(索尼Xperia Z1的Andr​​oid 5.1.1)这工作的几乎的完美。有一些bug和怪癖,但总的来说,我可以一直找到我的手机上的所有图像在我的应用程序,并点击他们查看详细信息。

The course required us to write a ContentProvider, so I've got a query() function which essentially fetches data from the MediaStore, and returns a cursor to MainActivity's GridView. On my device, at least, (Sony Xperia Z1, Android 5.1.1) this works almost perfectly. There are some bugs and quirks, but by and large I can consistently find all images on my phone in my app, and click on them to view details.

然而,当我试图在我朋友的索​​尼Xperia Z3安装应用程序,一切都失败了。无图像显示,虽然我明明检查实际上有〜100张照片他的手机上。同样在另一个朋友的电话(全新三星S6): - (

However, when I tried installing the app on my friend's Sony Xperia Z3, everything failed. No images showed up, although I obviously checked there were in fact ~100 photos on his phone. Same on another friend's phone (brand new Samsung S6) :-(

这是主要问题。在我的手机,在东西的作品,二次臭虫涉及当一个新的拍照相机,它不会自动加载到我的应用程序(如缩略图)。看来我需要弄清楚如何触发扫描,或者需要任何加载/生成新的拇指。这也是我的愿望清单上相当高的。

This is The Main Problem. On my phone, where stuff works, the "secondary" bugs involve when a new photo is taken by the camera, it's not automatically loaded into my app (as a thumbnail). It seems I need to figure out how to trigger a scan, or whatever is needed to load/generate new thumbs. That's also quite high on my wish list.

正如我所说的,我相信这一切真的应该是很简单的,所以也许我所有的困难表明,我在完全错误的方式接近这一问题? 这里是我的查询()函数这样做的:

As I said, I'm confident all this really ought to be quite simple, so maybe all my difficulties indicate I'm approaching the problem in the entirely wrong way? Here's what my query() function is doing:


  1. 获取所有缩略图光标,从 MediaStore.Media.Thumbnails.EXTERNAL_CONTENT_URI

获取所有图像的光标,从 MediaStore.Media.Images.EXTERNAL_CONTENT_URI

get a cursor of all images, from MediaStore.Media.Images.EXTERNAL_CONTENT_URI

加入其中,在 MediaStore.Media.Thumbnails.IMAGE_ID = MediaStore.Media.Images._ID 使用 CursorJoiner

返回结果 retCursor (如生产的连接)

return the resulting retCursor (as produced in the join)

- 请找这个previous后满code

-- please find full code in this previous post.

虽然这个的看起来的正确的是(对我),也许这真的不是走这个路?我与缩略图一起加入拇指和图像的方式,这样我可以显示一些元数据(例如拍摄日期),在GridView。我已经发现的问题向加盟,特别是因为如果我简化,只加载到拇指在GridView,那么这一切工作正常 - 也对我的朋友的电话。 (随着加载新的照片除外)。

Although this looks correct (to me), maybe it's really not the way to go about this? I'm joining thumbs and images, by the way, such that I can show some meta data (e.g. date taken) along with the thumbnail, in the GridView. I've identified the problem to the joining, in particular, because if I simplify this to only loading thumbs into the GridView, then this all works fine -- also on my friend's phone. (With the exception of loading new photos.)

不知怎的,我的假设是 IMAGE_ID _ID 始终保持一致是不正确的?我已经看到了AirPair <​​/A>一个帖子,描述类似画廊的应用程序,并有教程其实去这个略有不同。而不是试图加入光标,他得到缩略图光标并遍历它,<一个href=\"https://github.com/rexstjohn/UltimateAndroidCameraGuide/blob/master/camera/src/main/java/com/ultimate/camera/utilities/PhotoGalleryImageProvider.java\"相对=nofollow>使用到MediaStore 各个查询图像添加数据......但是,这是最有效的方式做到这一点?
- 然而,他的解决方案的确实的加入缩略图上的ID对应的图像:

Somehow, my assumption that IMAGE_ID and _ID are always consistent is not correct? I've seen a post on AirPair, describing a similar gallery app, and there the tutorial actually goes about this slightly differently. Rather than attempting to join cursors, he gets the thumbnails cursor and iterates over it, adding data from Images using individual queries to the MediaStore... But is that the most efficient way to do this? - Nevertheless, his solution does join the thumbnail to the corresponding image on ID:

Cursor imagesCursor = context.getContentResolver().query(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 
            filePathColumn, 
            MediaStore.Images.Media._ID + "=?", new String[]{imageId},  // NB!
            null);

总而言之,我需要用以下帮助:


  • 我是正确的查询MediaStore?

  • 是安全的加入拇指和图像,在ID - ?在任何时候都将是稳定/同步

  • 怎么我的应用程序自动生成/获取的新图像缩略图?

推荐答案

好吧,看来我终于想通这一切了。想我会分享这个位置,对于其他人谁可能会感兴趣。

OK, so it seems I finally figured all this out. Thought I'd share this here, for anyone else who might be interested.

什么是我想要达到什么目的?


    在设备上(通过MediaStore)
  • 查询缩略图和图像

  • 加入到这些一个光标,有序的降序的(顶部最新图片)

  • 处理缺失缩略图
  • 的情况下,
  • Query thumbnails and images on device (via MediaStore)
  • Join these into one cursor, ordered descending (newest images on top)
  • Handle the case of missing thumbnails

经过大量的试验和错误,以及玩弄的MediaStore,我已经了解到,缩略图表(MediaStore.Images.Thumbnails)不能预计将高达最新的,在任何给定的时间。有将会的失踪缩略图图像,反之亦然(孤儿缩略图)。特别是当相机应用需要一个新的照片,显然它不会立即创建缩略图。直到图库应用(或同等学历)被打开时,缩略图表更新。

After lots of trial and error, and playing around with the MediaStore, I've learned that the thumbnails table (MediaStore.Images.Thumbnails) can not be expected to be up-to-date, at any given time. There will be images missing thumbnails, and vice versa (orphaned thumbnails). Especially when the camera app takes a new photo, apparently it doesn't immediately create a thumbnail. Not until the Gallery app (or equivalent) is opened, is the thumbnail table updated.

我如何工作的自己解决此问题的各种有益的建议,主要集中在刚刚查询图像表(MediaStore.Images.Media),然后,不知何故,在一个时间延长光标缩略图一行。虽然这没有工作,就引起了应用程序是非常缓慢的,消耗了大量的内存〜2000图像设备上。

I got various helpful suggestions on how to work myself around this problem, mainly centered on just querying the images table (MediaStore.Images.Media) and then, somehow, extend the cursor with thumbnails one row at a time. While that did work, it caused the app to be extremely slow and consumed a lot of memory for ~2000 images on my device.

这真的的有可能只是JOIN(左外连接)与图像表中的缩略图表,这样,我们得到的所有图像和缩略图当这些存在。否则,我们离开缩略图数据列,只是产生这些特定失踪缩略图自己。什么是真正酷的是实际的插入的这些缩略图到MediaStore,但我还没看着呢。

It really should be possible to simply JOIN (left outer join) the thumbnails table with the images table, such that we get all images and the thumbnails when these exist. Otherwise, we leave the thumbnail DATA column to null, and just generate those particular missing thumbnails ourselves. What would be really cool is to actually insert those thumbnails into the MediaStore, but that I have not looked into yet.

这一切的主要问题是使用 CursorJoiner 。出于某种原因,它需要两个光标在的升序排列的,让我们说的ID。然而,第一意味着最早的映像,从而真正使一个蹩脚的画廊应用程序。我发现CursorJoiner可以上当,然而,成简单地通过 ID *允许排序从大到小的顺序( - 1)

The main problem with all this was using the CursorJoiner. For some reason, it requires both cursors to be ordered in ascending order, let's say on ID. However, that means oldest images first, which really makes for a crappy gallery app. I found that the CursorJoiner can be "fooled", however, into permitting descending order by simply ordering by ID*(-1):

Cursor c_thumbs = getContext().getContentResolver().query(
                    MediaStore.Images.Thumnails.EXTERNAL_CONTENT_URI,
                    null, null, null, 
                    "(" + MediaStore.Images.Thumnails.IMAGE_ID + "*(-1))");

Cursor c_images= getContext().getContentResolver().query(
                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    null, null, null, 
                    "(" + MediaStore.Images.Media._ID + "*(-1))");

只要行匹配,不过,这工作正常(即 BOTH 情况)。但是,当你碰上行,其中无论光标是唯一的(即例)颠倒顺序弄乱了在CursorJoiner类的内部运作。然而,在左,右光标一个简单的补偿就足以重新调整的加入,得到它回到正轨。注意 moveToNext()的moveTo previous()来电。

As long as the rows match up, though, this works fine (the BOTH case). But when you run into rows where either cursor is unique (the LEFT or RIGHT cases) the reversed ordering messes up the inner workings of the CursorJoiner class. However, a simple compensation on the left and right cursors is sufficient to "re-align" the join, getting it back on track. Note the moveToNext() and moveToPrevious() calls.

// join these and return
// the join is on images._ID = thumbnails.IMAGE_ID
CursorJoiner joiner = new CursorJoiner(
        c_thumbs, new String[] { MediaStore.Images.Thumnails.IMAGE_ID },  // left = thumbnails
        c_images, new String[] { MediaStore.Images.Media._ID }   // right = images
);

String[] projection = new String{"thumb_path", "ID", "title", "desc", "datetaken", "filename", "image_path"};

MatrixCursor retCursor = new MatrixCursor(projection);

try {
    for (CursorJoiner.Result joinerResult : joiner) {

        switch (joinerResult) {
            case LEFT:
                // handle case where a row in cursorA is unique
                // images is unique (missing thumbnail)

                // we want to show ALL images, even (new) ones without thumbnail!
                // data = null will cause a temporary thumbnail to be generated in PhotoAdapter.bindView()

                retCursor.addRow(new Object[]{
                        null, // data
                        c_images.getLong(1), // image id
                        c_images.getString(2), // title
                        c_images.getString(3),  // desc
                        c_images.getLong(4),  // date
                        c_images.getString(5),  // filename
                        c_images.getString(6)
                });

                // compensate for CursorJoiner expecting cursors ordered ascending...
                c_images.moveToNext();
                c_thumbs.moveToPrevious();
                break;

            case RIGHT:
                // handle case where a row in cursorB is unique
                // thumbs is unique (missing image)

                // compensate for CursorJoiner expecting cursors ordered ascending...
                c_thumbs.moveToNext();
                c_images.moveToPrevious();
                break;

            case BOTH:

                // handle case where a row with the same key is in both cursors
                retCursor.addRow(new Object[]{
                        c_thumbs.getString(1), // data
                        c_images.getLong(1), // image id
                        c_images.getString(2), // title
                        c_images.getString(3),  // desc
                        c_images.getLong(4),  // date
                        c_images.getString(5),  // filename
                        c_images.getString(6)
                });

                break;
        }
    }
} catch (Exception e) {
    Log.e("myapp", "JOIN FAILED: " + e);
}

c_thumbs.close();
c_images.close();

return retCursor;

然后,在PhotoAdapter类,它创造了我的 GridView控件元素和从ContentProvider的(返回光标将数据绑定到这些retCursor 以上),我创建了以下方式缩略图(当 thumb_path 字段是

Then, in the "PhotoAdapter" class, which creates elements for my GridView and binds data into these from the cursor returned from the ContentProvider (retCursor above), I create a thumbnail in the following manner (when the thumb_path field is null):

String thumbData = cursor.getString(0);  // thumb_path
if (thumbData != null) {
    Bitmap thumbBitmap;
    try {
        thumbBitmap = BitmapFactory.decodeFile(thumbData);
        viewHolder.iconView.setImageBitmap(thumbBitmap);
    } catch (Exception e) {
        Log.e("myapp", "PhotoAdapter.bindView() can't find thumbnail (file) on disk (thumbdata = " + thumbData + ")");
        return;
    }

} else {

    String imgPath = cursor.getString(6);   // image_path
    String imgId = cursor.getString(1);  // ID 
    Log.v("myapp", "PhotoAdapter.bindView() thumb path for image ID " + imgId + " is null. Trying to generate, with path = " + imgPath);

    try {
        Bitmap thumbBitmap = ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(imgPath), 512, 384);
        viewHolder.iconView.setImageBitmap(thumbBitmap);
    }  catch (Exception e) {
        Log.e("myapp", "PhotoAdapter.bindView() can't generate thumbnail for image path: " + imgPath);
        return;
    }
}

这篇关于查询MediaStore:加入缩略图和图像(上ID)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆