Android configura Volley para usar desde el caché

Intento crear y usar un caché para una respuesta JSON del servidor.

Por ejemplo:

almacenar en caché los objetos JSON en la memoria interna y usarlos cuando no tenemos una conexión a Internet.

En el siguiente código de ejemplo, no puedo encontrar ningún documento sobre cómo almacenarlo en caché con Volley y reutilizarlo cuando el encabezado del servidor para la actualización no caduque.

De esta manera: establezca la caducidad en el encabezado y use el caché e intente cargar nuevamente después de la caducidad.

Estoy tratando de establecer el mecanismo de caché para este método:

 private void makeJsonArryReq() { JsonArrayRequest req = new JsonArrayRequest(Const.URL_JSON_ARRAY, new Response.Listener() { @Override public void onResponse(JSONArray response) { msgResponse.setText(response.toString()); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }); AppController.getInstance().addToRequestQueue(req,tag_json_arry); } 

Método de caché:

 public static Cache.Entry parseIgnoreCacheHeaders(NetworkResponse response) { long now = System.currentTimeMillis(); Map headers = response.headers; long serverDate = 0; String serverEtag = null; String headerValue; headerValue = headers.get("Date"); if (headerValue != null) { serverDate = HttpHeaderParser.parseDateAsEpoch(headerValue); } serverEtag = headers.get("ETag"); final long cacheHitButRefreshed = 3 * 60 * 1000; // in 3 minutes cache will be hit, but also refreshed on background final long cacheExpired = 24 * 60 * 60 * 1000; // in 24 hours this cache entry expires completely final long softExpire = now + cacheHitButRefreshed; final long ttl = now + cacheExpired; Cache.Entry entry = new Cache.Entry(); entry.data = response.data; entry.etag = serverEtag; entry.softTtl = softExpire; entry.ttl = ttl; entry.serverDate = serverDate; entry.responseHeaders = headers; return entry; } 

Tenga en cuenta que si el servicio web admite la salida de almacenamiento en caché, no tiene que utilizar CacheRequest continuación, ya que Volley guardará automáticamente en caché.


Para su problema, uso algunos códigos dentro de parseCacheHeaders (y parseCacheHeaders códigos de @ oleksandr_yefremov ). El siguiente código lo he probado. Por supuesto, también puede usarse para JsonArrayRequest . ¡Espero que esto ayude!

  JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(0, mUrl, new Response.Listener() { @Override public void onResponse(JSONObject response) { try { mTextView.setText(response.toString(5)); } catch (JSONException e) { mTextView.setText(e.toString()); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }) { @Override protected Response parseNetworkResponse(NetworkResponse response) { try { Cache.Entry cacheEntry = HttpHeaderParser.parseCacheHeaders(response); if (cacheEntry == null) { cacheEntry = new Cache.Entry(); } final long cacheHitButRefreshed = 3 * 60 * 1000; // in 3 minutes cache will be hit, but also refreshed on background final long cacheExpired = 24 * 60 * 60 * 1000; // in 24 hours this cache entry expires completely 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 jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); return Response.success(new JSONObject(jsonString), cacheEntry); } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } catch (JSONException e) { return Response.error(new ParseError(e)); } } @Override protected void deliverResponse(JSONObject response) { super.deliverResponse(response); } @Override public void deliverError(VolleyError error) { super.deliverError(error); } @Override protected VolleyError parseNetworkError(VolleyError volleyError) { return super.parseNetworkError(volleyError); } }; MySingleton.getInstance(this).addToRequestQueue(jsonObjectRequest); 

ACTUALIZAR :

Si quieres una clase base, consulta los siguientes códigos:

 public class CacheRequest extends Request { private final Response.Listener mListener; private final Response.ErrorListener mErrorListener; public CacheRequest(int method, String url, Response.Listener listener, Response.ErrorListener errorListener) { super(method, url, errorListener); this.mListener = listener; this.mErrorListener = errorListener; } @Override protected Response parseNetworkResponse(NetworkResponse response) { Cache.Entry cacheEntry = HttpHeaderParser.parseCacheHeaders(response); if (cacheEntry == null) { cacheEntry = new Cache.Entry(); } final long cacheHitButRefreshed = 3 * 60 * 1000; // in 3 minutes cache will be hit, but also refreshed on background final long cacheExpired = 24 * 60 * 60 * 1000; // in 24 hours this cache entry expires completely 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; return Response.success(response, cacheEntry); } @Override protected void deliverResponse(NetworkResponse response) { mListener.onResponse(response); } @Override protected VolleyError parseNetworkError(VolleyError volleyError) { return super.parseNetworkError(volleyError); } @Override public void deliverError(VolleyError error) { mErrorListener.onErrorResponse(error); } } 

Luego, en MainActivity, puedes llamar así

 CacheRequest cacheRequest = new CacheRequest(0, mUrl, new Response.Listener() { @Override public void onResponse(NetworkResponse response) { try { final String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); JSONObject jsonObject = new JSONObject(jsonString); mTextView.setText(jsonObject.toString(5)); } catch (UnsupportedEncodingException | JSONException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { mTextView.setText(error.toString()); } }); MySingleton.getInstance(this).addToRequestQueue(cacheRequest); 

ACTUALIZAR CON EL CÓDIGO DE FUENTE COMPLETO:

MainActivity.java:

 package com.example.cachevolley; import android.content.Context; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; import android.widget.Toast; import com.android.volley.Cache; import com.android.volley.NetworkResponse; import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.HttpHeaderParser; import com.android.volley.toolbox.Volley; import org.json.JSONException; import org.json.JSONObject; import java.io.UnsupportedEncodingException; public class MainActivity extends AppCompatActivity { private final Context mContext = this; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final TextView textView = (TextView) findViewById(R.id.textView); RequestQueue queue = Volley.newRequestQueue(this); String url = "http://192.168.0.100/apitest"; CacheRequest cacheRequest = new CacheRequest(0, url, new Response.Listener() { @Override public void onResponse(NetworkResponse response) { try { final String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); JSONObject jsonObject = new JSONObject(jsonString); textView.setText(jsonObject.toString(5)); Toast.makeText(mContext, "onResponse:\n\n" + jsonObject.toString(), Toast.LENGTH_SHORT).show(); } catch (UnsupportedEncodingException | JSONException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Toast.makeText(mContext, "onErrorResponse:\n\n" + error.toString(), Toast.LENGTH_SHORT).show(); } }); // Add the request to the RequestQueue. queue.add(cacheRequest); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } private class CacheRequest extends Request { private final Response.Listener mListener; private final Response.ErrorListener mErrorListener; public CacheRequest(int method, String url, Response.Listener listener, Response.ErrorListener errorListener) { super(method, url, errorListener); this.mListener = listener; this.mErrorListener = errorListener; } @Override protected Response parseNetworkResponse(NetworkResponse response) { Cache.Entry cacheEntry = HttpHeaderParser.parseCacheHeaders(response); if (cacheEntry == null) { cacheEntry = new Cache.Entry(); } final long cacheHitButRefreshed = 3 * 60 * 1000; // in 3 minutes cache will be hit, but also refreshed on background final long cacheExpired = 24 * 60 * 60 * 1000; // in 24 hours this cache entry expires completely 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; return Response.success(response, cacheEntry); } @Override protected void deliverResponse(NetworkResponse response) { mListener.onResponse(response); } @Override protected VolleyError parseNetworkError(VolleyError volleyError) { return super.parseNetworkError(volleyError); } @Override public void deliverError(VolleyError error) { mErrorListener.onErrorResponse(error); } } } 

Archivo manifiesto

             

Archivo de diseño:

    

Si la respuesta está tomando desde el servidor utilizando String Request, entonces simplemente reemplace la línea

 return Response.success(new JSONObject(jsonString), cacheEntry); 

con este

 return Response.success(new String(jsonString), cacheEntry); 

Funciona en mi caso. Prueba con tu propio código.