M. Nasir Javaid
M. Nasir Javaid

Reputation: 5990

Android: Volley does not work offline with cache

I have added volley for request to get Json object, If wifi is turned on then it takes data but does not get in case of offline mode even cache is enabled for the request.

I do the following code

public class VolleySingleton extends Application
{
    public static final String TAG = VolleySingleton.class.getSimpleName();
    private RequestQueue mRequestQueue;
    private static VolleySingleton mInstance;
    private ImageLoader mImageLoader;
    private final String DEFAULT_CACHE_DIR = "sl_cache";

    @Override
    public void onConfigurationChanged(Configuration newConfig)
    {
        super.onConfigurationChanged(newConfig);
    }

    @Override
    public void onCreate()
    {
        super.onCreate();
        mInstance = this;
    }

    public static synchronized VolleySingleton getInstance()
    {
        return mInstance;
    }

    public ImageLoader getImageLoader()
    {
        getRequestQueue();
        if (mImageLoader == null)
        {
            mImageLoader = new ImageLoader(this.mRequestQueue, new LruBitmapCache());
        }
        return this.mImageLoader;
    }

    public <T> void addToRequestQueue(Request<T> req, String tag)
    {
        // set the default tag if tag is empty
        req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
        getRequestQueue().add(req);
    }

    public <T> void addToRequestQueue(Request<T> req)
    {
        req.setTag(TAG);
        getRequestQueue().add(req);
    }

    public void cancelPendingRequests(Object tag)
    {
        if (mRequestQueue != null)
        {
            mRequestQueue.cancelAll(tag);
        }
    }

    public RequestQueue getRequestQueue()
    {
        if (mRequestQueue == null)
        {
            Cache cache = new DiskBasedCache(getCacheDir(), 1024 * 1024 * 10); // 10MB cap
            Network network = new BasicNetwork(new HurlStack());
            mRequestQueue = new RequestQueue(cache, network);
            mRequestQueue.start();
        }
        return mRequestQueue;
    }
}


private void getData(String url, String tag)
{
            final JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>()
            {
                @Override
                public void onResponse(JSONObject response)
                {
                    Log.wtf("HOME", response.toString());
                    String result = parseData(response.toString());
                    postProcessing(result);
                    //SocialLadder.getInstance().getRequestQueue().getCache().invalidate(url, true);
                }


            }, new Response.ErrorListener()
            {
                @Override
                public void onErrorResponse(VolleyError error)
                {
                    VolleyLog.wtf("HOME", "Error: " + error.getMessage());
                    stopRefresher();
                }
            })
            {
                @Override
                protected Response<JSONObject> parseNetworkResponse(NetworkResponse response)
                {                        
                    try
                    {
                        String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
                        return !jsonString.isEmpty() ? Response.success(new JSONObject(jsonString), HttpHeaderParser.parseCacheHeaders(response)) : Response.success(new JSONObject(), HttpHeaderParser.parseCacheHeaders(response));
                    }
                    catch (JSONException ex)
                    {
                        ex.printStackTrace();
                    }
                    catch (UnsupportedEncodingException e)
                    {
                        e.printStackTrace();
                    }
                    return null;
                }
            };
            jsonObjReq.setShouldCache(true);
            VolleySingleton.getInstance().addToRequestQueue(jsonObjReq, tag);
}

Please help, I want to cache my screen data.

Edit

Cache Data

 private String getCache(String url)
    {
        String data = "";
        Cache cache = VolleySingleton.getInstance().getRequestQueue().getCache();
        Cache.Entry entry = cache.get(url);
        if (entry != null)
        {
            try
            {
                data = new String(entry.data, "UTF-8");
                // handle data, like converting it to xml, json, bitmap etc.,
            }
            catch (UnsupportedEncodingException e)
            {
                e.printStackTrace();
            }
        }
        /*else
        {
            // Cached response doesn't exists. Make network call here
        }*/
        return data;
    }

Upvotes: 2

Views: 8181

Answers (2)

Vipin Sahu
Vipin Sahu

Reputation: 1451

Just add this line in **BasicNetwork* class or modify it as follow

  @Override
  public NetworkResponse performRequest(Request<?> request) throws VolleyError {
    long requestStart = SystemClock.elapsedRealtime();
    while (true) {

        HttpResponse httpResponse = null;
        byte[] responseContents = null;
        Map<String, String> responseHeaders = Collections.emptyMap();
        try {
         if(!ConnectivityUtils.isNetworkEnabled(BBApplication.getContext())) {
                return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED,
                        request.getCacheEntry().data, responseHeaders, true);
            }

            // Gather headers.
            Map<String, String> headers = new HashMap<String, String>();
            addCacheHeaders(headers, request.getCacheEntry());
            httpResponse = mHttpStack.performRequest(request, headers);
            StatusLine statusLine = httpResponse.getStatusLine();
            int statusCode = statusLine.getStatusCode();
            responseHeaders = convertHeaders(httpResponse.getAllHeaders());
            // Handle cache validation.


            if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
                Cache.Entry entry = request.getCacheEntry();

                if (entry == null) {
                    return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
                }

                // A HTTP 304 response does not have all header fields. We
                // have to use the header fields from the cache entry plus
                // the new ones from the response.
                // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5
                entry.responseHeaders.putAll(responseHeaders);
                return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data, entry.responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
            }
            // Some responses such as 204s do not have content.  We must check.
            if (httpResponse.getEntity() != null) {
                responseContents = entityToBytes(httpResponse.getEntity());
            } else {
                // Add 0 byte response as a way of honestly representing a
                // no-content request.
                responseContents = new byte[0];
            }

            // if the request is slow, log it.
            long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
            logSlowRequests(requestLifetime, request, responseContents, statusLine);

            if (statusCode < 200 || statusCode > 299) {
                throw new IOException();
            }
            return new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
        } catch (SocketTimeoutException e) {
            attemptRetryOnException("socket", request, new TimeoutError());
        } catch (ConnectTimeoutException e) {
            attemptRetryOnException("connection", request, new TimeoutError());
        } catch (NoHttpResponseException e) {
            attemptRetryOnException("socket", request, new TimeoutError());
        } catch (UnknownHostException e) {
            attemptRetryOnException("socket", request, new TimeoutError());
        } catch (MalformedURLException e) {
            throw new RuntimeException("Bad URL " + request.getUrl(), e);
        } catch (IOException e) {
            int statusCode = 0;
            NetworkResponse networkResponse = null;
            if (httpResponse != null) {
                statusCode = httpResponse.getStatusLine().getStatusCode();
            } else {
                throw new NoConnectionError(e);
            }
            VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
            if (responseContents != null) {
                networkResponse = new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
                if (statusCode == HttpStatus.SC_UNAUTHORIZED || statusCode == HttpStatus.SC_FORBIDDEN) {
                    attemptRetryOnException("auth", request, new AuthFailureError(networkResponse));
                } else {
                    // TODO: Only throw ServerError for 5xx status codes.
                    throw new ServerError(networkResponse);
                }
            } else {
                throw new NetworkError(networkResponse);
            }
        }
    }
}

and for data request expiry you can change the Cached.Entry using using own HttpHeaderParser

Click for BasicNetwork

What is this code will do it will check for internet connection and Network call and revert if it has cached copy .

Note The API response should be cache-able because Volley only cache data if Response Header permits . See here for Cached Control Header

Upvotes: 6

mmlooloo
mmlooloo

Reputation: 18977

In order to cache anything with Volley you need to have two things:

1) server allows you to cache it. it usually appears in a cache control tag in the HTTP header.

2) you save it or in this scenario you tell the Volly to save.

so i think your problem is in number one. that means the server dose not allow you to cache those files, in order to confirm my answer you can do one of these things:

  1. download this plug in (RESTClient) for mozilla and send your request and check the header file for cache control. if the server dose not allow you to cache you will see something like below image, notice cache control tag

enter image description here

  1. set break point in headerValue = headers.get("Cache-Control"); at HttpHeaderParse class and see whats going on when Volley wants to parse the cache control tag.

Upvotes: 5

Related Questions