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
相关产品推荐
相关产品推荐

