【问题标题】:How to I get the cached Bitmap I downloaded using Volley ImageLoader?如何获取使用 Volley ImageLoader 下载的缓存位图?
【发布时间】:2013-07-15 15:37:00
【问题描述】:

问题:我有 X 数量的 ImageView,我正在像这样动态添加:

for (int i=2; i < result.size(); i++) {
        // instantiate image view
        ImageView mImageView = new ImageView(this);
        mImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
        mImageView.setBackgroundResource(R.drawable.selectable_background_theme);
        mImageView.setOnClickListener(this);

        // download image and display it
        mImageLoader.get(result.get(i), ImageLoader.getImageListener(mImageView, R.drawable.ic_logo, R.drawable.ic_action_refresh));

        // add images to container view
        mLlDescContent.addView(mImageView);
    }

希望能够单击图像并将其全屏显示在另一个活动中。我已经阅读了几种方法,例如传递 Uri 或将实际位图作为字节数组传递。

问题:如何获取 Uri 或使用 Volley ImageLoader 下载的实际位图。 LruCache 我正在使用我在这里找到的 BitmapLruCache:Android Volley ImageLoader - BitmapLruCache parameter?。有人可以帮助我解决这个问题或任何想法来实现我的目标。

我在上面的代码之后尝试了这个,没有:

Bitmap mBitmap = VolleyInstance.getBitmapLruCache().getBitmap(result.get(2));
mIvAuthorImg.setImageBitmap(mBitmap);

编辑:如果我重新请求图片:

mImageLoader.get(result.get(i), ImageLoader.getImageListener(mImageView, R.drawable.ic_logo, R.drawable.ic_action_refresh));

图像是从缓存中加载的,但是如果我尝试直接从缓存中访问图像:

Bitmap mBitmap = VolleyInstance.getBitmapLruCache().getBitmap(result.get(2));
mIvAuthorImg.setImageBitmap(mBitmap);

图片无法加载。我希望能够操纵图像,例如在将其传递给下一个活动之前调整其大小。

【问题讨论】:

  • 你不是已经有了第一次下载图片时的url吗?
  • 是的,结果是一个包含所有图片 url 的 ArrayList
  • 好的,如果你有 url 列表,那到底是什么问题?
  • 我想在使用 volley ImageLoader 下载后从缓存中检索图像。 getBitmap(url) 似乎不起作用。如果它已经被缓存,我不想重新下载它。我想从缓存中获取位图,然后将位图传递给下一个活动。
  • 如果图像存在于缓存中,我相信图像将从缓存中启动,而不是再次下载图像。你检查过这不是已经发生的吗?这就是其他用于图像下载的库的工作方式。

标签: android bitmap android-imageview android-volley


【解决方案1】:

Volley 取决于您对缓存的实现,以实现成功的高效缓存。 ImageLoader 的构造函数接受 ImageCache,这是 Volley 中用于保存和加载位图的简单接口。

public ImageLoader(RequestQueue queue, ImageCache imageCache)

引用ImageCache接口的Javadoc:

简单的缓存适配器接口。如果提供给 ImageLoader,它将在分派给 Volley 之前用作 L1 缓存。实现不得阻塞。建议使用 LruCache 实现。

达尔文是对的。如果您请求图像并且它存在于缓存中,它将从缓存而不是从 Web 加载。这应该是您的情况,因为您正在加载和呈现图像,如果单击该图像,则应从新活动的缓存中显示该图像。

您说它不起作用,也许您的实现没有针对您的用例进行优化。你用的是什么类型的缓存?是否有 Volley 团队推荐的集中式 RequestQueueImageLoader

查看this question,它与您的不完全相同,但可能对您有所帮助。它有一个简单的 LRU 缓存实现。

希望有帮助!

编辑:

Volley 的重点是不用担心实现细节。你要图吗?它将以最好和最快的方式为您加载它(从内存中,如果它不存在通过网络)。这正是你应该看待它的方式。检索缓存然后查看它不是 IMO 的正确方法。

现在,如果您想操作位图,您有几个选择,最好的 IMO 是实现您自己的 Image Listener 将其传递给 get() 方法而不是默认方法。

类似这样的:

public class MyImageListener implements ImageListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        // handle errors
    }

    @Override
    public void onResponse(ImageContainer response, boolean isImmediate) {
        Bitmap bitmap = response.getBitmap();
        if (bitmap != null) {

            //                    
            // manipulations
            //

            // assuming mView is a reference to your ImageView
            mView.setImageBitmap(bitmap);
        } else {
            // display placeholder or whatever you want
        }
    }
}

来自 Javadoc:

调用流程是这样的:

  1. 在附加到请求后,将调用 onResponse(response, true) 以反映任何已经可用的缓存数据。如果 数据可用,response.getBitmap() 将不为空。

  2. 网络响应返回后,只会出现以下一种情况:

    • onResponse(response, false) 会在图片加载完毕后被调用。

    • 如果加载图片出错,将调用onErrorResponse。

【讨论】:

  • 我正在使用与您的链接相同的 LruCache。我将 ImageLoader 实例化为单例。图片显示得很好。我想要做的是能够在用户点击后将图像绑定到另一个活动中。因此,如果我在下一个活动中进行相同的 Imageloader 调用,它将从缓存中加载,因为 ImageLoader 已经在上一个活动中下载?正如达尔文所说。因为使用 get(url) 或 getBitmap(url) 手动检索图像不起作用。
  • 谢谢,这正是我需要知道的。
  • 仅在您使用视图时有效,如果您想获取缓存的图像并将其保存到文件或将其传递到电子邮件以进行共享怎么办?
  • 不正确。 ImageListener 与视图完全正交。将响应插入视图是完全取决于您的选项。你可以实现它来做你想做的事。一旦onResponse 被调用并且你有对图像的引用,你可以将它保存到文件中,传递它或者做任何你想做的事情。
  • @ItaiHanski 在另一个活动权利实践中提出新的NetworkImage 请求吗?如果存在,它会从缓存中加载图像吗?
【解决方案2】:

目前在 volley 中存在一个错误(我 70% 确定这是一个错误),如果未指定缓存过期时间(例如,如果您从 S3 存储桶中获取图像,而您从未 - expires 设置),您将始终从网络重新下载。

您可以通过查看 HttpHeaderParser 并将相关位(这并不完全疯狂,因为您必须包含 volley 源代码)更改为:

// Cache-Control takes precedence over an Expires header, even if both exist and Expires
// is more restrictive.
if (hasCacheControl) {
    softExpire = now + maxAge * 1000;
} else if (serverDate > 0 && serverExpires >= serverDate) {
    // Default semantic for Expire header in HTTP specification is softExpire.
    softExpire = now + (serverExpires - serverDate);
} else if (serverExpires == 0) {
    softExpire = Long.MAX_VALUE;
}

然后您可以将 Uri 作为参数传递给打开事物的活动。该解决方案具有令人羡慕的特性,如果在启动活动和显示位图之间出现问题并且图像发生问题,您仍将重新下载它并且一切都会正常工作。这可能永远不会/很少发生,但很高兴知道正确性得以保留。

【讨论】:

    猜你喜欢
    • 2013-08-20
    • 1970-01-01
    • 2013-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-06
    • 2015-07-09
    相关资源
    最近更新 更多