HttpResponseCache在Android Lollipop中无法正常工作

4

我一直在我的应用中成功使用HttpResponseCache,但当我的手机更新到Lollipop后,我意识到HttpResponseCache现在永远不会被“命中”,总是进行网络请求。我已经确认在Android Lollipop之前的版本中仍然工作正常。 也许是我做错了什么,在新的Android更改中出现了问题。

有人有任何想法吗?

我的代码:

Application类,onCreate...

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
        try {
            File httpCacheDir = new File(getApplicationContext().getCacheDir()
                    , "http");
            long httpCacheSize = 10 * 1024 * 1024;
            HttpResponseCache.install(httpCacheDir, httpCacheSize);
        } catch (IOException e) {
            Log.i(TAG, "HTTP response cache installation failed:" + e);
        }
    } else {
        try {
            File httpCacheDir = new File(getCacheDir(), "http");
            long httpCacheSize = 10 * 1024 * 1024;
            Class.forName("android.net.http.HttpResponseCache")
                    .getMethod("install", File.class, long.class)
                    .invoke(null, httpCacheDir, httpCacheSize);
        } catch (Exception e) {
                Log.i(TAG, "HTTP response cache installation failed:" + 
        }
    }

请求管理函数

public static InputStream fetchInputStream(String strURL, boolean forceRefresh)
        throws IOException {

    HttpURLConnection mHttpConn = null;
    InputStream inputStream = null;
    URL url = new URL(strURL);
    HttpResponseCache cache;

    try {
        mHttpConn = (HttpURLConnection) url.openConnection();

        if (forceRefresh) {
            mHttpConn.addRequestProperty("Cache-Control", "no-cache");
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            cache = HttpResponseCache.getInstalled();
            if (cache != null) {

                    Log.i("TEST CACHE", "TEST PETICION: Req count: "
                            + cache.getRequestCount() + ", hit count "
                            + cache.getHitCount() + ", netWork count "
                            + cache.getNetworkCount() + "   size = "
                            + cache.size() + " <-----------------");

            }
        }

        mHttpConn.setUseCaches(true);
        mHttpConn.setDefaultUseCaches(true);
        mHttpConn.setRequestMethod("GET");
        mHttpConn.setConnectTimeout(30000);
        mHttpConn.setReadTimeout(30000);
        mHttpConn.connect();

        if (mHttpConn.getResponseCode() == HttpURLConnection.HTTP_OK) {
            inputStream = mHttpConn.getInputStream();
        }


    } catch (IOException ex) {
        Log.e("NetworkConnectionManager InputStream", "Exception opening ["
                + strURL + "] ->", ex);
        mHttpConn.disconnect();

        throw ex;
    }

    return inputStream;
}

每个请求后

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
        HttpResponseCache cache = HttpResponseCache.getInstalled();

        if (cache != null) {
            cache.flush();
        }
    }

示例请求头:

  • Cache-Control → max-age=300
  • 连接 → keep-alive
  • 内容编码 → gzip
  • 内容类型 → application/json; charset=utf-8
  • 日期 → Wed, 08 Apr 2015 12:37:35 GMT
  • 过期时间 → Wed, 08 Apr 2015 12:42:35 GMT
  • 最后修改时间 → Wed, 08 Apr 2015 12:37:35 GMT
  • 服务器 → nginx
  • 传输编码方式 → chunked
  • 变化 → Accept-Encoding
  • X-Cached → MISS

嘿,查看这个:https://code.google.com/p/android/issues/detail?id=81357。基本上它说,如果你在清单中没有添加“WRITE_EXTERNAL_STORAGE”权限,可能会出现一个错误导致缓存填充失败。也许你可以尝试添加它来确认这是否是你在这里遇到的问题。 - mdelolmo
这个问题在Lollipop中没有得到解决。有人能帮我解决这个问题吗?我希望可能有什么诀窍可以解决它。 - Shreyash Mahajan
2个回答

2
几天以来我一直遇到这个问题,最终发现这是个问题。在 Marshmallow 中它已被修复。
这是 Lollipop 中的一个 bug,因为默认情况下 Vary -> Accept-Encoding 标头被填充但没有写入缓存而导致缓存失败。
下面是问题链接:

https://code.google.com/p/android/issues/detail?id=162475

解决方法是明确设置Accept-Encoding:
Accept-Encoding -> gzip 或者
Accept-Encoding -> identity
在读取输入流时,您需要添加这个。
String encoding = urlConnection.getHeaderField("Content-Encoding");
boolean gzipped = encoding!=null && encoding.toLowerCase().contains("gzip");
Inputstream inputStream;
if(gzipped)
    inputStream = new GZIPInputStream(urlConnection.getInputStream());
else
    inputstream = urlConnection.getInputStream();

1
这对我不起作用。还有其他解决方案吗? @stevehs17,你有什么建议来解决这个问题吗? - Shreyash Mahajan
@iDroidExplorer:我已经有一段时间没有处理这个问题了,但我记得我放弃使用HttpResponseCache的整个想法,因为它在不同的Android操作系统版本中无法保持一致性。 - stevehs17

1
我遇到过类似的问题。我期望图片被缓存,但实际上并没有被缓存。
问题最终被确定为在将InputStream读入Bitmap后我没有关闭它。
您的fetchInputStream返回一个从http连接获取的InputStream,请确保正确关闭它。
Android http缓存只有在关闭连接的InputStream后才会保存资源。

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