如何获取使用Volley ImageLoader下载的缓存位图?

时间:2013-07-17 07:29:49

标签: android bitmap android-imageview android-volley

问题:我有一定数量的ImageViews,我正在动态添加:

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或将实际的Bitmap作为字节数组传递。

问题:如何获取我使用Volley ImageLoader下载的Uri或实际位图。 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);

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

2 个答案:

答案 0 :(得分:5)

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

public ImageLoader(RequestQueue queue, ImageCache imageCache)

来自ImageCache接口的Javadoc的引用:

  

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

Darwind是对的。如果您请求图像并且它存在于缓存中,则它将从缓存而不是从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()将为非null。

  2.   
  3. 网络响应返回后,只会发生以下一种情况:

         
        
    • 如果图像已加载,将调用onResponse(response,false)。

           

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

    •   
  4.   

答案 1 :(得分:1)

如果没有指定缓存到期(例如,如果您从S3存储桶中获取了一个从未有过的图像),则会出现一个错误(我有70%确定这是一个错误)。到期设置),您将始终从网络重新下载。

你可以通过检查HttpHeaderParser并更改相关位(这不是完全疯狂,因为你必须包括凌空源代码)来解决这个问题:

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