You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android使用Volley处理缓存:联网时仅获取服务器数据

解决Volley联网时仅显示服务器数据、断网时显示缓存的问题

看起来你遇到的核心问题是Volley默认缓存策略导致联网时会同时加载缓存和服务器数据,出现两者混合的情况。要实现联网时仅用服务器数据,断网时用缓存的效果,我们可以从请求缓存策略控制、错误回调读取缓存两个方面调整:

步骤1:添加网络状态判断方法

首先需要判断设备当前是否联网,以此为依据设置不同的请求规则:

private boolean isNetworkAvailable() {
    ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    if (connectivityManager == null) return false;
    NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
    return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}

别忘了在AndroidManifest.xml中添加必要权限:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />

步骤2:调整请求逻辑与缓存策略

修改你的NotesView()方法,针对联网/断网状态设置不同的缓存控制,同时优化数据解析逻辑避免缓存与服务器数据混合:

private void NotesView() {
    User user = PreferenceManager.getInstance(getApplicationContext()).getUser();
    int id = user.getId();

    StringRequest stringRequest = new StringRequest(Request.Method.POST, SERVER_URL, 
        new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                try {
                    JSONArray jsonArray = new JSONArray(response);
                    // 关键:先清空数据源,彻底避免缓存数据残留
                    mNotesList.clear();
                    for (int i = 0; i < jsonArray.length(); i++) {
                        JSONObject jsonObject = jsonArray.getJSONObject(i);
                        // 解析你的数据对象并添加到数据源
                        // 示例:Note note = new Note(jsonObject.getInt("id"), jsonObject.getString("content"));
                        // mNotesList.add(note);
                    }
                    mAdapter.notifyDataSetChanged();
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }, 
        new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                // 断网时,从Volley缓存中读取数据
                Cache cache = MySingleton.getInstance(getApplicationContext()).getRequestQueue().getCache();
                // 构造缓存key:Volley POST请求的缓存key是URL+编码后的参数
                String cacheKey = SERVER_URL + "?" + "id=" + id;
                Cache.Entry entry = cache.get(cacheKey);
                if (entry != null) {
                    try {
                        String cachedResponse = new String(entry.data, HttpHeaderParser.parseCharset(entry.responseHeaders));
                        // 解析缓存数据并更新UI
                        JSONArray jsonArray = new JSONArray(cachedResponse);
                        mNotesList.clear();
                        for (int i = 0; i < jsonArray.length(); i++) {
                            JSONObject jsonObject = jsonArray.getJSONObject(i);
                            // 解析数据添加到数据源
                            // Note note = new Note(jsonObject.getInt("id"), jsonObject.getString("content"));
                            // mNotesList.add(note);
                        }
                        mAdapter.notifyDataSetChanged();
                    } catch (UnsupportedEncodingException | JSONException e) {
                        e.printStackTrace();
                    }
                }
            }
        }) {
        // 保留原有缓存逻辑,用于断网时读取最新缓存
        @Override
        protected Response<String> parseNetworkResponse(NetworkResponse response) {
            try {
                Cache.Entry cacheEntry = HttpHeaderParser.parseCacheHeaders(response);
                if (cacheEntry == null) {
                    cacheEntry = new Cache.Entry();
                }
                final long cacheHitButRefreshed = 3 * 60 * 1000; // 3分钟后后台自动刷新缓存
                final long cacheExpired = 24 * 60 * 60 * 1000; // 24小时后缓存完全过期
                long now = System.currentTimeMillis();
                final long softExpire = now + cacheHitButRefreshed;
                final long ttl = now + cacheExpired;
                cacheEntry.data = response.data;
                cacheEntry.softTtl = softExpire;
                cacheEntry.ttl = ttl;
                String headerValue;
                headerValue = response.headers.get("Date");
                if (headerValue != null) {
                    cacheEntry.serverDate = HttpHeaderParser.parseDateAsEpoch(headerValue);
                }
                headerValue = response.headers.get("Last-Modified");
                if (headerValue != null) {
                    cacheEntry.lastModified = HttpHeaderParser.parseDateAsEpoch(headerValue);
                }
                cacheEntry.responseHeaders = response.headers;
                final String string = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
                return Response.success(string, cacheEntry);
            } catch (UnsupportedEncodingException e) {
                return Response.error(new ParseError(e));
            }
        }

        @Override
        protected Map<String, String> getParams() throws AuthFailureError {
            Map<String, String> params = new HashMap<>();
            params.put("id", String.valueOf(id));
            return params;
        }
    };

    // 根据网络状态设置缓存策略
    if (isNetworkAvailable()) {
        // 联网时:强制请求网络,同时更新缓存
        CacheControl forceNetwork = new CacheControl.Builder().forceNetwork().build();
        stringRequest.setCacheControl(forceNetwork);
    } else {
        // 断网时:强制使用缓存
        CacheControl forceCache = new CacheControl.Builder().forceCache().build();
        stringRequest.setCacheControl(forceCache);
    }

    MySingleton.getInstance(getApplicationContext()).addToRequestQueue(stringRequest);
}

核心逻辑说明

  • 联网场景:通过forceNetwork()强制Volley跳过缓存直接请求服务器,请求成功后会自动更新缓存(依赖你原有的parseNetworkResponse逻辑),同时在onResponse中先清空数据源再添加服务器数据,彻底避免缓存残留导致的重复问题。
  • 断网场景:通过forceCache()强制Volley使用缓存,当请求失败(断网)时,在onErrorResponse中手动读取Volley缓存并解析显示。
  • 缓存key匹配:POST请求的缓存key由URL+编码后的参数组成,我们手动构造匹配格式的key,确保能正确读取到对应缓存数据。

内容的提问来源于stack exchange,提问作者Neston Marica

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:50:09