Volley 图片缓存

15

我正在尝试理解Volley的图像缓存。我有一个包含GridView的碎片,在其中加载了大约12-30张图片。这些图片是从服务器检索的,我正在使用NetworkImageView来加载这些图片。

我能够在NetworkImageView中显示图片,一切都正常。但是,当我从一个片段切换到另一个,并返回到上一个片段时,在 LogCat 中,我发现Volley正在尝试再次获取图片。

我读过Volley自动处理图像缓存。当第一个片段中的图像被缓存时,为什么当我从第二个片段回到第一个片段时它仍然会尝试获取图像?首先,LogCat数据显示的是Volley的图像请求吗?还是其他东西...

以下是我的代码:

onCreate()

queue = Volley.newRequestQueue(getActivity());
imageLoader = new ImageLoader(queue, new ImageLoader.ImageCache() {
    private final LruCache<String, Bitmap> mCache = new LruCache<String, Bitmap>(
            10);

    public void putBitmap(String url, Bitmap bitmap) {
        mCache.put(url, bitmap);
    }

    public Bitmap getBitmap(String url) {
        return mCache.get(url);
    }
});

第一次加载碎片时的Logcat:

02-18 14:21:20.724: D/Volley(14713): [4944] BasicNetwork.logSlowRequests: HTTP response for request=<[ ] http://xx.files.wordpress.com/2014/02/screen-shot-2014-02-17-at-11-57-29-pm.png 0x800c5bdc LOW 2> [lifetime=3782], [size=398563], [rc=200], [retryCount=0]
02-18 14:21:20.874: D/Volley(14713): [4943] BasicNetwork.logSlowRequests: HTTP response for request=<[ ] http://xx.files.wordpress.com/2014/02/st-vincent.jpg 0x800c5bdc LOW 3> [lifetime=3941], [size=501475], [rc=200], [retryCount=0]
02-18 14:21:20.894: D/Volley(14713): [1] Request.finish: 4181 ms: [ ] http://xx.files.wordpress.com/2014/02/screen-shot-2014-02-17-at-11-57-29-pm.png 0x800c5bdc LOW 2
02-18 14:21:20.974: D/Volley(14713): [1] Request.finish: 4260 ms: [ ] http://xx.files.wordpress.com/2014/02/st-vincent.jpg 0x800c5bdc LOW 3
02-18 14:21:20.994: D/dalvikvm(14713): GC_FOR_ALLOC freed 1914K, 6% free 68371K/72184K, paused 11ms, total 11ms
02-18 14:21:20.994: I/dalvikvm-heap(14713): Grow heap (frag case) to 72.368MB for 5843106-byte allocation
02-18 14:21:21.014: D/dalvikvm(14713): GC_FOR_ALLOC freed 1K, 5% free 74076K/77892K, paused 15ms, total 15ms
02-18 14:21:21.074: D/Volley(14713): [1] Request.finish: 4336 ms: [ ] http://xx.files.wordpress.com/2014/02/underwater.gif 0x800c5bdc LOW 8
02-18 14:21:21.214: D/Volley(14713): [4945] BasicNetwork.logSlowRequests: HTTP response for request=<[ ] http://xx.files.wordpress.com/2014/02/screen-shot-2014-02-17-at-4-24-04-pm.png 0x800c5bdc LOW 5> [lifetime=4155], [size=482380], [rc=200], [retryCount=0]
02-18 14:21:21.244: D/Volley(14713): [1] Request.finish: 4494 ms: [ ] http://xx.files.wordpress.com/2014/01/albarn-everyday-robots.jpg 0x800c5bdc LOW 9
02-18 14:21:21.274: D/Volley(14713): [1] Request.finish: 4551 ms: [ ] http://xx.files.wordpress.com/2014/02/screen-shot-2014-02-17-at-4-24-04-pm.png 0x800c5bdc LOW 5
02-18 14:21:21.994: D/Volley(14713): [1] Request.finish: 5244 ms: [ ] http://xx.files.wordpress.com/2014/02/macdemarco_baby.jpg 0x800c5bdc LOW 10
02-18 14:21:22.934: D/Volley(14713): [1] Request.finish: 6183 ms: [ ] http://xx.files.wordpress.com/2014/01/nenehcherry_lank01.jpg 0x800c5bdc LOW 11

第二次回到相同的片段时:刚访问了第二个片段,回到了第一个片段——中间没有太大的差距...

02-18 14:27:46.164: D/dalvikvm(14713): GC_FOR_ALLOC freed 29047K, 26% free 91776K/122752K, paused 23ms, total 23ms
02-18 14:27:47.994: D/dalvikvm(14713): GC_FOR_ALLOC freed 2957K, 21% free 97010K/122752K, paused 20ms, total 20ms
02-18 14:27:48.274: D/Volley(14713): [1] Request.finish: 3244 ms: [ ] http://xx.files.wordpress.com/2014/02/screen-shot-2014-02-17-at-2-58-16-pm.png 0x800c5bdc LOW 6
02-18 14:27:48.294: D/dalvikvm(14713): GC_FOR_ALLOC freed 2007K, 21% free 97932K/122752K, paused 14ms, total 14ms
02-18 14:27:48.324: D/Volley(14713): [4956] BasicNetwork.logSlowRequests: HTTP response for request=<[ ] http://xx.files.wordpress.com/2014/02/screen-shot-2014-02-17-at-11-57-29-pm.png 0x800c5bdc LOW 2> [lifetime=3272], [size=398563], [rc=200], [retryCount=0]
02-18 14:27:48.484: D/Volley(14713): [1] Request.finish: 3456 ms: [ ] http://xx.files.wordpress.com/2014/02/screen-shot-2014-02-17-at-11-57-29-pm.png 0x800c5bdc LOW 2
02-18 14:27:48.974: D/dalvikvm(14713): GC_FOR_ALLOC freed 1030K, 15% free 104815K/122752K, paused 56ms, total 56ms
02-18 14:27:49.054: D/Volley(14713): [1] Request.finish: 4022 ms: [ ] http://xx.files.wordpress.com/2014/02/screen-shot-2014-02-17-at-4-24-04-pm.png 0x800c5bdc LOW 5
02-18 14:27:49.314: D/Volley(14713): [1] Request.finish: 4276 ms: [ ] http://xx.files.wordpress.com/2014/01/albarn-everyday-robots.jpg 0x800c5bdc LOW 9
02-18 14:27:49.374: D/Volley(14713): [1] Request.finish: 4325 ms: [ ] http://xx.files.wordpress.com/2014/01/nenehcherry_lank01.jpg 0x800c5bdc LOW 11
02-18 14:27:49.404: D/Volley(14713): [1] Request.finish: 4355 ms: [ ] http://xx.files.wordpress.com/2014/02/macdemarco_baby.jpg 0x800c5bdc LOW 10
02-18 14:27:49.654: D/dalvikvm(14713): GC_FOR_ALLOC freed 1456K, 12% free 108705K/122752K, paused 27ms, total 27ms
02-18 14:27:49.734: D/Volley(14713): [1] Request.finish: 4691 ms: [ ] http://xx.files.wordpress.com/2014/02/underwater.gif 0x800c5bdc LOW 8
02-18 14:27:50.304: D/dalvikvm(14713): GC_FOR_ALLOC freed 11584K, 16% free 103314K/122752K, paused 47ms, total 47ms
02-18 14:27:50.334: D/Volley(14713): [1] Request.finish: 5281 ms: [ ] http://xx.files.wordpress.com/2014/02/echo-and-the-bunnymen.jpg 0x800c5bdc LOW 12

正如链接所示,Volley正在访问相同的URL。 Volley是试图从服务器获取图像吗?还是只显示它正在从缓存中加载的URL?

我如何使Volley缓存图像?如果它现在没有正确处理缓存,那么根据上面的代码,我应该怎么做才能实现它?

我尝试将maxSize值从10更改为100*1024*1024(100MB),但这并没有阻止Volley输出相同的值。

7个回答

11

Volley没有直接提供缓存选项。你必须使用Volley提供的工具来制作自己的缓存。请参见网络图像缓存,Jake Wharton已经写了关于使用Volley进行缓存机制的文章。Jake Wharton的Volley定制


好的,我会看一下。在查看其他问题时,我发现了这个链接:https://dev59.com/QGQn5IYBdhLWcg3woIYF#16684652 我可以使用这种方式来缓存我的图片吗? - Vamsi Challa
1
可能是这样。但是这个缓存是关于内存缓存的,如果你想要进行磁盘缓存,你需要使用Jake的解决方案。 - Tofeeq Ahmad
好的,谢谢你的帮助。我会检查Jake的解决方案并回复你。已点赞。 - Vamsi Challa
2
请注意不要使用基于磁盘的缓存,比如Jake Wharton编写的那种,在Volley期望内存缓存的情况下。 - Itai Hanski
@ItaiHanski 在某些情况下可能会造成损害,但在大多数情况下,一旦应用程序启动,重新下载所有图像是不可行的。尤其是当你有很多图片时。 - Tofeeq Ahmad
@Sameer 如果你提供了一个磁盘缓存而不是内存缓存,那么你将使用2个磁盘缓存,因为Volley已经有一个磁盘缓存了。这很糟糕,因为不仅性能会变差,而且你将占用两倍的磁盘空间,其中大部分都是重复的内容。 - Itai Hanski

1
请考虑使用Glide,它是Android推荐的用于在应用程序中加载图片的工具。与Volley相比,Glide提供了自动图像缓存。
要将Glide添加到您的应用程序中,请按以下步骤进行:
步骤1)更新build.gradle文件。
dependencies {
    compile 'com.github.bumptech.glide:glide:3.6.1'
    compile 'com.android.support:support-v4:19.1.0'
  }

步骤二)在清单文件中添加INTERNET权限。
<uses-permission android:name="android.permission.INTERNET" />

步骤三:在你的布局中添加 ImageView。
<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/imageView"
    >
</ImageView>

步骤4)在Activity中使用Glide
    //Initialize ImageView
    ImageView imageView = (ImageView) findViewById(R.id.imageView);

    //Loading image from below url into imageView
   Glide.with(this)
        .load("IMAGE URL HERE")
        .placeholder(R.drawable.placeholder)
        .error(R.drawable.imagenotfound)
        .override(200, 200);
        .centerCrop();
        .into(imageView);

Android Glide Library 上阅读更多


1
您可以在下面的链接中看到,我关于使用Jake Wharton的DiskLruCache和VolleyImageCacheExample实现图像缓存的问题的继续。它按预期工作,并且图像已被缓存。感谢您的所有帮助。
链接:如何使用Jake Wharton的DiskLruCache与Volley实现?

1

你是否将Volley作为单例使用?如果没有,并且你没有为requestQueue使用共同的上下文,那么它不会按照你的期望工作。 Volley这一部分的文档特别没有帮助(至少自从我上次使用它以来是这样)。一旦正确配置,它将按照你的期望从缓存中读取/写入。

这是一个GitHub项目,其中包含可以与示例一起使用的VolleySingleton类: CypressNorth/Volley-Singleton

这是一篇博客文章,更详细地描述了设置过程: 为NetworkImageView设置Android Google Volley ImageLoader


0
你可以检查一下,我已经为 Volley 启用了 L1 和 L2 缓存机制。 带缓存的 Volley。请确保响应头中启用了缓存控制。

0

虽然很粗鲁,但它能工作 :)

package it.dataware.passaeprendi.app.util;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.util.LruCache;

import com.android.volley.VolleyLog;
import com.android.volley.toolbox.ImageLoader;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;

// https://dev59.com/dmYq5IYBdhLWcg3w-FTQ
// https://dev59.com/CWoy5IYBdhLWcg3wMLSj

public class DiskBitmapCache implements ImageLoader.ImageCache {
private File   cacheDir;

// ...
private  static final String CACHE_PATH      = "dataware/passaeprendi/imagechache/";
private  static final String CACHE_FULL_PATH = Environment.getExternalStorageDirectory() + "/" + CACHE_PATH;
private  static final int    MAX_IMAGE_AGE   = 5; // in days

private  static final BitmapFactory.Options options = new BitmapFactory.Options();
static {
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
}

public DiskBitmapCache() {
    cacheDir = new File(CACHE_FULL_PATH);
    cacheDir.mkdirs();
}

private static  ImageLoader.ImageCache imageLoaderCache = new ImageLoader.ImageCache() {
    private final LruCache<String, Bitmap> mCache = new LruCache<>(30);

    public void putBitmap(String url, Bitmap bitmap) {
        mCache.put(url, bitmap);
    }
    public Bitmap getBitmap(String url) {
        return mCache.get(url);
    }
};

public Bitmap getBitmap(String url) {

    final String volleyFileName = getFilenameForKey(url);

    final Bitmap bitmapL1 = imageLoaderCache.getBitmap(volleyFileName);
    if (bitmapL1 != null) {
        // VolleyLog.d("taken from cache L1 :" + url + " -> " + volleyFileName + ".");
        return bitmapL1;
    }

    final File volleyCacheFile = new File(cacheDir, volleyFileName);

    if (!volleyCacheFile.exists()) {
        return null;
    }

    // =======================================
    // age check
    // =======================================

    long diff = new Date().getTime() - volleyCacheFile.lastModified();

    if (diff > MAX_IMAGE_AGE * 24 * 60 * 60 * 1000) {
        volleyCacheFile.delete();
        return null;
    }

    // =======================================
    // load from disk
    // =======================================

    Bitmap bitmap = BitmapFactory.decodeFile(volleyCacheFile.getAbsolutePath(), options);

    if (bitmap != null) {
        //     VolleyLog.d("taken from cache L2 :" + url + " -> " + volleyFileName + ".");
        imageLoaderCache.putBitmap(volleyFileName, bitmap);
    }

    // VolleyLog.d("taken from cache L2 :" + url + " -> " + volleyFileName + ".");
    return bitmap;
}

public void putBitmap(String url, Bitmap bitmap) {
    final String volleyFileName = getFilenameForKey(url);

    File volleyCacheFile = new File(cacheDir, volleyFileName);

    try {
        // ...
        FileOutputStream fos = null;
        volleyCacheFile.createNewFile();
        fos = new FileOutputStream(volleyCacheFile, false);
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
        fos.flush();
        fos.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

// Volley creates a filename for the url with the following function, so we'll use the same function
// for translating the url back to said filename
private String getFilenameForKey(String key) {
    int firstHalfLength = key.length() / 2;

    // ..
    String  localFilename   = String.valueOf(key.substring(0, firstHalfLength)  .hashCode());
            localFilename  += String.valueOf(key.substring(firstHalfLength)     .hashCode());
            localFilename  += ".jpg";

    return localFilename;
}
}    

我希望这能帮助到某个人。


0

我发现使用带有DiskBasedCacheRequestQueue是缓存图像最简单的方法。我的目标是减少带宽而不是加载时间,这也可以使内存占用低。

 val cacheSizeInMegabytes = 5
 val cacheSizeInBytes = cacheSizeInMegabytes * 1024 * 1024
 val cacheDir = File(context.cacheDir, "volleyCache")
 val cache = DiskBasedCache(cacheDir, cacheSizeInBytes)

 val httpStack = HurlStack()
 val networkStack = BasicNetwork(httpStack)

 val queue = RequestQueue(cache, networkStack)
 queue.start()

然后只需使用queue,并确保使用request.setShouldCache(true)(或不使用)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接