X09
X09

Reputation: 3956

Issues with Volley caching mechanism

I have a website which publishes news on daily basis.

Now, I'm sending a JsonArrayRequest to retrieve and parse the title and summary of each news published on the website. The parsed items are then used to populate RecyclerView.

The problem I'm having is the way volley implements caching .

Let's take this scenario: the app is installed, launched and the RecyclerView is populated. The user reads the news and forgets about the app

Later, the user launches the app and the items are fetched and RecyclerView is populated.

Between the first and the second launch, new news are published on the website. But in the second launch, these new items are not displayed. However, if the user manually go to app settings and clear cache of the app, and relaunch, the new items are displayed.

You get my point?

While I don't want to disable Volley caching, how do I make it to always fetch new items?

EDIT

MainActivity

public class MainActivity extends AppCompatActivity {

    private final String TAG = "MainActivity";



    //Creating a list of newss
    private List<NewsItems> mNewsItemsList;

    //Creating Views
    private RecyclerView recyclerView;
    private RecyclerView.Adapter adapter;
    private RecyclerView.LayoutManager layoutManager;
    private ProgressDialog mProgressDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "onCreate called");

        //Initializing Views
        recyclerView = (RecyclerView) findViewById(R.id.news_recycler);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);


        //Initializing the newslist
        mNewsItemsList = new ArrayList<>();
        adapter = new NewsAdapter(mNewsItemsList, this);

        recyclerView.setAdapter(adapter);

        if (NetworkCheck.isAvailableAndConnected(this)) {

            //Calling method to get data
            getData();
        } else {
            //Codes for building Alert Dialog
            alertDialogBuilder.setPositiveButton(R.string.alert_retry, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    if (!NetworkCheck.isAvailableAndConnected(mContext)) {
                        alertDialogBuilder.show();
                    } else {
                        getData();
                    }

                }
            });
            alertDialogBuilder.setNegativeButton(R.string.alert_cancel, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    finish();

                }
            });
            alertDialogBuilder.show();

        }


    }



    //This method will get data from the web api
    private void getData(){


        Log.d(TAG, "getData called");
        //Codes for Showing progress dialog

        //Creating a json request
        JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(ConfigNews.GET_URL + getNumber(),
                new Response.Listener<JSONArray>() {
                    @Override
                    public void onResponse(JSONArray response) {
                        Log.d(TAG, "onResponse called");
                        //Dismissing the progress dialog
                        if (mProgressDialog != null) {
                            mProgressDialog.hide();
                        }
                   //calling method to parse json array
                        parseData(response);

                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {

                    }
                });

        //Creating request queue
        RequestQueue requestQueue = Volley.newRequestQueue(this);

        //Adding request to the queue
        requestQueue.add(jsonArrayRequest);

    }

    //This method will parse json data
    private void parseData(JSONArray array){
        Log.d(TAG, "Parsing array");

        for(int i = 0; i<array.length(); i++) {
            NewsItems newsItem = new NewsItems();
            JSONObject jsonObject = null;
            try {
                jsonObject = array.getJSONObject(i);
                newsItem.setNews_title(jsonObject.getString(ConfigNews.TAG_VIDEO_TITLE));
                newsItem.setNews_body(jsonObject.getString(ConfigNews.TAG_VIDEO_BODY));

            } catch (JSONException w) {
                w.printStackTrace();
            }
            mNewsItemsList.add(newsItem);


        }

        adapter.notifyItemRangeChanged(0, adapter.getItemCount());
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy called");
        if (mProgressDialog != null){
            mProgressDialog.dismiss();
            Log.d(TAG, "mProgress dialog dismissed");

        }
    }

}

Upvotes: 0

Views: 1376

Answers (1)

kalin
kalin

Reputation: 3576

Option 1) Delete Cache

before you make a call you can delete the whole cache by myDiskBasedCache.clear() or specific entries by myDiskBasedCache.remove(entryUrl)

Option 2) Custom CacheParser (in the Request)

    @Override
protected Response<Bitmap> parseNetworkResponse(NetworkResponse response) {
    Response<Bitmap> resp = super.parseNetworkResponse(response);
    if(!resp.isSuccess()) {
        return resp;
    }
    long now = System.currentTimeMillis();
    Cache.Entry entry = resp.cacheEntry;
    if(entry == null) {

        entry = new Cache.Entry();
        entry.data = response.data;
        entry.responseHeaders = response.headers;
        entry.ttl = now + 60 * 60 * 1000;  //keeps cache for 1 hr
    }
    entry.softTtl = 0; // will always refresh

    return Response.success(resp.result, entry);
}

Option 3) send requests that does not cache

myRequest.setShouldCache(false);

Option 4) use custom Cache implementation

UPDATE:

Example with your code:

    //Creating a json request
        JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(ConfigNews.GET_URL + getNumber(),
                new Response.Listener<JSONArray>() {
                    @Override
                    public void onResponse(JSONArray response) {
                        Log.d(TAG, "onResponse called");
                        //Dismissing the progress dialog
                        if (mProgressDialog != null) {
                            mProgressDialog.hide();
                        }
                   //calling method to parse json array
                        parseData(response);

                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {

                    }
                }) {
 @Override
    protected Response<JSONArray> parseNetworkResponse(NetworkResponse response) {
        Response<JSONArray> resp = super.parseNetworkResponse(response);
        if(!resp.isSuccess()) {
            return resp;
        }
        long now = System.currentTimeMillis();
        Cache.Entry entry = resp.cacheEntry;
        if(entry == null) {

            entry = new Cache.Entry();
            entry.data = response.data;
            entry.responseHeaders = response.headers;
            entry.ttl = now + 60 * 60 * 1000;  //keeps cache for 1 hr
        }
        entry.softTtl = 0; // will always refresh

        return Response.success(resp.result, entry);
    }
};

UPDATE 2

Http protocol caching supports many ways to define how the client can cache responses and when to update them. Volley simplifies those rules to:

  • entry.ttl (time to live in ms) if greater than the current time then cache can be used otherwise fresh request needs to be made

and

  • entry.softTtl (soft time to live in ms :) if greater than the current time cache is absolutely valid and no request to the server needs to be made, otherwise new request is still made (even if the ttl is good) and if there is a change new response will be delivered.

    note that if ttl is valid and softTtl is not you can receive 2 onResponse calls

Upvotes: 1

Related Questions