I'm using volly to retrieve data and its work perfectly, except that my json array is not storing in the cache.
Here is my code:
private void getCacheValue() {
Cache cache = AppController.getInstance().getRequestQueue().getCache();
Cache.Entry entry = cache.get(Endpoints.product_url);
if(entry != null){
Log.w("Logdata:", ""+ entry.toString());
try {
String data = new String(entry.data, "UTF-8");
JSONArray jsonArray = new JSONArray(data);
// handle data, like converting it to xml, json, bitmap etc.,
Log.v("Hello", data);
listProduct.clear();
for (int i = 0; i < jsonArray.length(); i++) {
try {
JSONObject object = jsonArray.getJSONObject(i);
ItemCategories image = new ItemCategories();
image.setCategoryItem(object.getString(key_title));
image.setUrlThumb(object.getString(key_image));
listProduct.add(image);
} catch (JSONException e) {
Log.e(TAG, "Json parsing error: " + e.getMessage());
}
}
adapterProductList.notifyDataSetChanged();
progressBarMain.setVisibility(View.GONE);
internetError.setVisibility(View.GONE);
recycleProductList.setVisibility(View.VISIBLE);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
Log.v("JSON EXCEPTION", "DECLINE");
}
} else {
if(isNetworkAvailable()) {
fetchImages();
} else {
progressBarMain.setVisibility(View.GONE);
internetError.setVisibility(View.VISIBLE);
}
}
}
private void fetchImages() {
JsonObjectRequest jsObjRequest =
new JsonObjectRequest(Request.Method.GET, Endpoints.product_url(String) null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
listProduct.clear();
try {
JSONArray routes = response.getJSONArray(key_product);
for (int i = 0; i < routes.length(); i++) {
JSONObject object = routes.getJSONObject(i);
ItemCategories categories = new ItemCategories();
categories.setCategoryItem(object.getString(key_title));
categories.setUrlThumb(object.getString(key_image));
listProduct.add(categories);
}
adapterProductList.notifyDataSetChanged();
progressBarMain.setVisibility(View.GONE);
internetError.setVisibility(View.GONE);
recycleProductList.setVisibility(View.VISIBLE);
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),
"Error: " + e.getMessage(),
Toast.LENGTH_LONG).show();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
}
});
// Adding request to request queue
AppController.getInstance().addToRequestQueue(jsObjRequest);
}
I have already declared Appcontroller in the manifest, but I don't know why caching is not working.
Here is my json_data
fetchImage() is working because there is data in recyclerview. However, when I try to retrieve the data offline it does show any because my cache can't store any data.
By default, Volley only caches data if Response Header permits.
Volley caches response on the basis of following response headers:
1. Cache-Control
2. Expires
3. maxAge
See below function for details :
public static Cache.Entry parseCacheHeaders(NetworkResponse response) {
long now = System.currentTimeMillis();
Map<String, String> headers = response.headers;
long serverDate = 0;
long lastModified = 0;
long serverExpires = 0;
long softExpire = 0;
long finalExpire = 0;
long maxAge = 0;
long staleWhileRevalidate = 0;
boolean hasCacheControl = false;
boolean mustRevalidate = false;
String serverEtag = null;
String headerValue;
headerValue = headers.get("Date");
if (headerValue != null) {
serverDate = parseDateAsEpoch(headerValue);
}
headerValue = headers.get("Cache-Control");
if (headerValue != null) {
hasCacheControl = true;
String[] tokens = headerValue.split(",");
for (int i = 0; i < tokens.length; i++) {
String token = tokens[i].trim();
if (token.equals("no-cache") || token.equals("no-store")) {
return null;
} else if (token.startsWith("max-age=")) {
try {
maxAge = Long.parseLong(token.substring(8));
} catch (Exception e) {
}
} else if (token.startsWith("stale-while-revalidate=")) {
try {
staleWhileRevalidate = Long.parseLong(token.substring(23));
} catch (Exception e) {
}
} else if (token.equals("must-revalidate") || token.equals("proxy-revalidate")) {
mustRevalidate = true;
}
}
}
headerValue = headers.get("Expires");
if (headerValue != null) {
serverExpires = parseDateAsEpoch(headerValue);
}
headerValue = headers.get("Last-Modified");
if (headerValue != null) {
lastModified = parseDateAsEpoch(headerValue);
}
serverEtag = headers.get("ETag");
// Cache-Control takes precedence over an Expires header, even if both exist and Expires
// is more restrictive.
if (hasCacheControl) {
softExpire = now + maxAge * 1000;
finalExpire = mustRevalidate
? softExpire
: softExpire + staleWhileRevalidate * 1000;
} else if (serverDate > 0 && serverExpires >= serverDate) {
// Default semantic for Expire header in HTTP specification is softExpire.
softExpire = now + (serverExpires - serverDate);
finalExpire = softExpire;
}
Cache.Entry entry = new Cache.Entry();
entry.data = response.data;
entry.etag = serverEtag;
entry.softTtl = softExpire;
entry.ttl = finalExpire;
entry.serverDate = serverDate;
entry.lastModified = lastModified;
entry.responseHeaders = headers;
return entry;
}
You can change default cache policy by overriding Request object.
You can override JsonObjectRequest like :
public class CustomJsonObjectRequest extends JsonObjectRequest {
public CustomJsonObjectRequest(int method, String url, JSONObject jsonRequest, Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {
super(method, url, jsonRequest, listener, errorListener);
}
public CustomJsonObjectRequest(String url, JSONObject jsonRequest, Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {
super(url, jsonRequest, listener, errorListener);
}
#Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));
return Response.success(new JSONObject(jsonString),
parseIgnoreCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JSONException je) {
return Response.error(new ParseError(je));
}
}
public static Cache.Entry parseIgnoreCacheHeaders(NetworkResponse response) {
long now = System.currentTimeMillis();
Map<String, String> 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;
}
}
Update your fetchImage function as:
private void fetchImages() {
CustomJsonObjectRequest jsObjRequest = new CustomJsonObjectRequest()
(Request.Method.GET, Endpoints.product_url, (String) null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
listProduct.clear();
try {
JSONArray routes = response.getJSONArray(key_product);
for (int i = 0; i < routes.length(); i++) {
JSONObject object = routes.getJSONObject(i);
ItemCategories categories = new ItemCategories();
categories.setCategoryItem(object.getString(key_title));
categories.setUrlThumb(object.getString(key_image));
listProduct.add(categories);
}
adapterProductList.notifyDataSetChanged();
progressBarMain.setVisibility(View.GONE);
internetError.setVisibility(View.GONE);
recycleProductList.setVisibility(View.VISIBLE);
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),
"Error: " + e.getMessage(),
Toast.LENGTH_LONG).show();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
}
});
// Adding request to request queue
AppController.getInstance().addToRequestQueue(jsObjRequest);
}
For reference, check Android Volley + JSONObjectRequest Caching
Related
I apply cache but it works only one time when I click on first item it shows data after that when I click on another it shows same data how t fix it any guidelines
Here is my code
String URL = "http://facekart.azanic.com/Data_show_all_.php";
final ProgressDialog progressDialog = new ProgressDialog(getContext());
progressDialog.setMessage("Fetcing, please wait...");
progressDialog.show();
StringRequest request = new StringRequest(Request.Method.POST, URL, new Response.Listener<String>() {
#Override
public void onResponse(String s) {
progressDialog.dismiss();
try {
JSONObject jsonObject = new JSONObject(s);
JSONArray jsonArray = jsonObject.getJSONArray("result");//getting array
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject1 = jsonArray.getJSONObject(i);
Itemssetget it = new Itemssetget();
it.setName(jsonObject1.getString("name"));
it.setPhonenumber_seller(jsonObject1.getString("phonenumber_seller"));
it.setPrice(jsonObject1.getString("price"));
it.setDiscountprice(jsonObject1.getString("discountprice"));
it.setUnits(jsonObject1.getString("units"));
it.setStock(jsonObject1.getString("stock"));
it.setId(jsonObject1.getString("key_auto"));
it.setImageurl("http://facekart.azanic.com/images/" + jsonObject1.getString("imageurl"));
if (it.getStock().toString().equals("In stock")) {
items_random.add(it);
}
}
if (!items_random.isEmpty() && getActivity() != null) {
myAdapter = new homebuyer_fruits_adapter(getActivity(), items_random, homebuyer.phone_number_shop);
myAdapter.notifyDataSetChanged();
Random_list.addHeaderView(random_v);
Random_list.setAdapter(myAdapter);
Random_list.setSmoothScrollbarEnabled(true);
loadingdataprogress.stopShimmerAnimation();
loadingdataprogress.setVisibility(View.INVISIBLE);
// Toast.makeText(getContext(),"ADDED",Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
Toast.makeText(getContext(), "Some error occurred -> " + volleyError, Toast.LENGTH_LONG).show();
;
}
}) {
#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; // 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 String(jsonString), cacheEntry);
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
}
}
#Override
protected void deliverResponse(String s) {
super.deliverResponse(s);
}
#Override
public void deliverError(VolleyError error) {
super.deliverError(error);
}
//adding parameters to send
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> parameters = new HashMap<String, String>();
parameters.put("s_number", homebuyer.phone_number_shop);
parameters.put("trig", "all");
return parameters;
}
};
RequestQueue rQueue = Volley.newRequestQueue(getContext());
rQueue.add(request);
Thanks in advance if any one help me in this I want every item click it shows data but first time it get from service second time it use from cache r any other method you can also suggest me How I smooth my app
I don't want to loading again and again
I am sending multiple request through for loop.
On response I get success or failure message, and I need to show this message in a AlertDialog.
My Problem is: when I am sending 10 request then I am getting 10 response hence 10 times dialogue is showing with response.
I want to show only one dialogue when all response will have come,and that dialogue should contain response according to their each and every request.
How can I do it.
code which I tried:
if (globalInstance.isNetworkAvailable(AddBookingList.this)) {
int si = checkedItems.size();
if (checkedItems.size() > 0) {
for (int i = 0; i < si; i++) {
int appid = checkedItems.get(i).getAppid();
int bookingId = checkedItems.get(i).getBookingid();
List<Contacts> con = db.getadvertisment(bookingId);
List<AddImages> img = db.getImagesbybookingId(bookingId);
String postXml = createxmlForPost(con, img);
sendDataToServer(postXml,appid, bookingId, si);
}
}
}
private void sendDataToServer(final String postXml, final int appid, final int bookingId, final int si) {
final ProgressDialog progressDialog = new ProgressDialog(this, R.style.AppCompatAlertDialogStyle);
progressDialog.setMessage("Please wait...");
progressDialog.setCancelable(false);
progressDialog.show();
try {
final RequestQueue queue = Volley.newRequestQueue(this);
JSONObject obj = new JSONObject();
obj.put("xmlData", postXml);
int socketTimeout = 30000;//30 seconds
final StringRequest postRequest = new StringRequest(Request.Method.POST, Constants.Rootpath + "PostBooking",
new Response.Listener<String>() {
#Override
public void onResponse(String st) {
if (progressDialog != null || progressDialog.isShowing()) {
progressDialog.dismiss();
}
try {
JSONArray response = new JSONArray(st);
for (int i = 0; i < response.length(); i++) {
JSONObject jsonObject = response.getJSONObject(i);
int status = jsonObject.getInt("Status");
String msg = jsonObject.getString("Msg");
String serverbooking_id = jsonObject.getString("BookingId");
if (status == 1) {
checkedItems.clear();
if (response.length() > 1) {
String newserverbooking_id = response.getJSONObject(0).getString("BookingId") + "\n" + response.getJSONObject(1).getString("BookingId");
db.updateBookingDetailsbyAppId(newserverbooking_id, appid, status);
} else {
db.updateBookingDetailsbyAppId(serverbooking_id, appid, status);
}
showDatainList();
globalInstance.showSuceessMessage(true, "Success!!! Your BookingID is: " + serverbooking_id, AddBookingList.this);
try {
List<Contacts> contacts = db.getAllBookingDetails();
for (int h = 0; h < contacts.size(); h++) {
locallySaveImagesinPhone(bookingId, contacts.get(h).get_serverbookingId());
}
} catch (IOException e) {
e.printStackTrace();
}
if (progressDialog.isShowing()) {
progressDialog.dismiss();
}
} else {
globalInstance.showFailureMessage(false, "Booking Failed." + msg, AddBookingList.this);
checkedItems.clear();
if (progressDialog.isShowing()) {
progressDialog.dismiss();
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
if (progressDialog != null || progressDialog.isShowing()) {
progressDialog.dismiss();
}
String msg = error.getMessage();
globalInstance.showFailureMessage(false, "Booking Failed.Please Try Again!!!", AddBookingList.this);
}
}
) {
#Override
protected Map<String, String> getParams() {
HashMap<String, String> params = new HashMap<>();
params.put("xmldata", postXml);
return params;
}
};
RetryPolicy policy = new DefaultRetryPolicy(socketTimeout, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
postRequest.setRetryPolicy(policy);
queue.add(postRequest);
} catch (JSONException e1) {
e1.printStackTrace();
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
}
}
}
As i understand your problem is calling globalInstance.showSuceessMessage() or globalInstance.showFailureMessage every time you get the response.
what i think might work is:
Instead of these two methods, define an Arraylist<String> and based on the
success or failure of the response add messages to it like "Success!!! Your BookingID is: " + serverbooking_id and "Booking Failed." + msg.
Define a method like showMessages() which has a dialogue containing the messages u added to arraylist before. then call it after where you called thesendDataToServer method which is in the if (checkedItems.size() > 0) block.
I get the following error:
Process: com.project.publiko, PID: 27061
java.lang.NoSuchFieldError: No static field INSTANCE of type Lorg/apache/http/message/BasicHeaderValueFormatter; in class Lorg/apache/http/message/BasicHeaderValueFormatter; or its superclasses (declaration of 'org.apache.http.message.BasicHeaderValueFormatter' appears in /system/framework/ext.jar)
at org.apache.http.entity.ContentType.toString(ContentType.java:153)
at org.apache.http.entity.mime.MultipartFormEntity.<init>(MultipartFormEntity.java:56)
at org.apache.http.entity.mime.MultipartEntityBuilder.buildEntity(MultipartEntityBuilder.java:236)
at org.apache.http.entity.mime.MultipartEntity.getEntity(MultipartEntity.java:119)
at org.apache.http.entity.mime.MultipartEntity.writeTo(MultipartEntity.java:180)
at com.project.publiko.CustomMultipartRequest.getBody(CustomMultipartRequest.java:57)
at com.android.volley.toolbox.HurlStack.addBodyIfExists(HurlStack.java:236)
at com.android.volley.toolbox.HurlStack.setConnectionParametersForRequest(HurlStack.java:210)
at com.android.volley.toolbox.HurlStack.performRequest(HurlStack.java:106)
at com.android.volley.toolbox.BasicNetwork.performRequest(BasicNetwork.java:93)
at com.android.volley.NetworkDispatcher.run(NetworkDispatcher.java:110)
Refer error line (Gradle):
android {
useLibrary 'org.apache.http.legacy'
}
public class CustomMultipartRequest extends Request < String > {
private Response.Listener < String > mListener = null;
private Response.ErrorListener mEListener;
private long cacheTimeToLive = 0;
//
private Map < String,
String > header;
MultipartEntity entity;
#Override
public Map < String,
String > getHeaders() throws AuthFailureError {
// you can add your custom headers here
HashMap < String, String > headers = new HashMap < > ();
return headers;
}
public CustomMultipartRequest(String url, Response.ErrorListener eListener, Response.Listener < String > rListener, MultipartEntity entity) {
super(Method.POST, url, eListener);
mListener = rListener;
mEListener = eListener;
this.entity = entity;
}
#Override
public String getBodyContentType() {
return entity.getContentType().getValue();
}
#Override
public byte[] getBody() throws AuthFailureError {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try { **
Error Line ** entity.writeTo(bos);
String entityContentAsString = new String(bos.toByteArray());
Log.e("volley", entityContentAsString);
} catch (IOException e) {
VolleyLog.e("IOException writing to ByteArrayOutputStream");
}
return bos.toByteArray();
}
#Override
protected void deliverResponse(String response) {
Log.d("DEBUG::Volley", response.toString());
System.out.println("VolleyQueue: Response Delivered for " + getTag() +
" (" + getSequence() + ")");
mListener.onResponse(response);
// TODO Auto-generated method stub
}
#Override
protected Response < String > parseNetworkResponse(NetworkResponse response) {
// TODO Auto-generated method stub
try {
// Volley does not handle null properly, so implement null response
// check
if (response.data.length == 0) {
byte[] responseData = "{}".getBytes("UTF8");
response = new NetworkResponse(response.statusCode,
responseData, response.headers, response.notModified);
}
String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(jsonString,
parseIgnoreCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
System.out.println("VolleyQueue: Encoding Error for " + getTag() +
" (" + getSequence() + ")");
return Response.error(new ParseError(e));
}
}
public Cache.Entry parseIgnoreCacheHeaders(NetworkResponse response) {
long now = System.currentTimeMillis();
Map < String, String > headers = response.headers;
long serverDate = 0;
String serverEtag;
String headerValue;
headerValue = headers.get("Date");
if (headerValue != null) {
serverDate = HttpHeaderParser.parseDateAsEpoch(headerValue);
}
serverEtag = headers.get("ETag");
final long cacheHitButRefreshed = 15 * 60 * 1000; //Fifteen Minutes
final long cacheExpired = cacheTimeToLive;
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;
}
#Override
public void deliverError(VolleyError error) {
super.deliverError(error);
}
}
Call to the class:
CustomMultipartRequest req = new CustomMultipartRequest(URL, //url where you want to send the multipart request
elistener, //instance of onErrorResponse Listener
rlistener, //instance of onResponse Listener
entityBuilder);
req.setShouldCache(false);
RequestQueue rq = Volley.newRequestQueue(context);
rq.add(req);
Can you help me to solve this error?
Thanks in advance ;)
Is a error of the library version
try with this versions
implementation 'org.apache.httpcomponents:httpclient:4.5.3'
api 'org.apache.httpcomponents:httpcore:4.4.6'
api 'org.apache.httpcomponents:httpmime:4.3.6'
implementation('org.apache.httpcomponents:httpmime:4.3.6') {
exclude module: 'httpclient'
}
implementation 'org.apache.httpcomponents:httpclient-android:4.3.5'
in my cache mechanism after add the request to the RequestQueue and try to fetch data from server, my cache method return multi duplicate result from server return json string
RequestQueue queue = Volley.newRequestQueue(this);
String url = Globals.getHostAddress() + "/get_latest_video";
items.clear();
CacheRequest cacheRequest = new CacheRequest(0, url, new Response.Listener<NetworkResponse>() {
#Override
public void onResponse(NetworkResponse response) {
try {
final String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
Log.e("allVideos", jsonString);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
// Add the request to the RequestQueue.
queue.add(cacheRequest);
server return this result:
{"id":12,"channel_id":7,"category_id":8}
Cache mechanism return :
{"id":12,"channel_id":7,"category_id":8},{"id":12,"channel_id":7,"category_id":8}
whats my code problem to cache data and using that?
CacheRequest class content:
public class CacheRequest extends Request<NetworkResponse> {
private final Response.Listener<NetworkResponse> mListener;
private final Response.ErrorListener mErrorListener;
public CacheRequest(int method, String url, Response.Listener<NetworkResponse> listener, Response.ErrorListener errorListener) {
super(method, url, errorListener);
this.mListener = listener;
this.mErrorListener = errorListener;
}
#Override
protected Response<NetworkResponse> 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);
}
}
UPDATED POST:
public class ActivityBootstrap extends Activity implements AdapterView.OnItemClickListener {
#InjectView(R.id.drawer_list)
ListView drawer_list;
#InjectView(R.id.drawer_layout)
DrawerLayout drawer_layout;
#InjectView(R.id.listView)
AsymmetricGridView listView;
private List<DrawerItem> drawer_items = new ArrayList<DrawerItem>();
private List<VideoItems> items = new ArrayList<>();
private DrawerAdatper drawer_adatper = null;
private boolean mDrawerState = false;
private VideoAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.inject(this);
RequestQueue queue = Volley.newRequestQueue(this);
String url = Globals.getHostAddress() + "/get_latest_video";
items.clear();
CacheRequest cacheRequest = new CacheRequest(0, url, new Response.Listener<NetworkResponse>() {
#Override
public void onResponse(NetworkResponse response) {
try {
final String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
Log.e("allVideos", jsonString);
JSONArray jsonArray = new JSONArray(jsonString);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject video_single_item = jsonArray.getJSONObject(i);
int video_id = video_single_item.getInt("id");
String video_thumbnail = video_single_item.getString("thumbnail");
int colSpan = Math.random() < 0.2f ? 2 : 1;
int rowSpan = colSpan;
VideoItems item = new VideoItems(colSpan, rowSpan, video_thumbnail,video_id);
items.add(item);
}
setUpListView(items);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
// Add the request to the RequestQueue.
queue.add(cacheRequest);
}
private void setUpListView(List video_array_items) {
final List<AsymmetricItem> items = new ArrayList<>();
adapter = new VideoListAdapter(this, video_array_items);
AsymmetricGridViewAdapter asymmetricAdapter =
new AsymmetricGridViewAdapter<>(this, listView, adapter);
listView.setAdapter(asymmetricAdapter);
listView.setRequestedColumnCount(3);
listView.setAdapter(getNewAdapter());
listView.setOnItemClickListener(this);
listView.setAllowReordering(true);
listView.isAllowReordering();
}
private AsymmetricGridViewAdapter<?> getNewAdapter() {
return new AsymmetricGridViewAdapter<>(this, listView, adapter);
}
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
int video_position = items.get(position).getVideo_id();
Intent intent = new Intent(ActivityBootstrap.this, ActivitySHowVideoDetaile.class);
intent.putExtra("video_id", video_position);
startActivity(intent);
}
}
UPDATED POST 2)
Result of Log.e("allVideos", jsonString); is :
10-28 09:51:46.016 17872-17872/pishguy.ir.asrebidree E/allVideos: [{"id":12,"thumbnail":"1445615983c92d10f1f3ee907150be1fdb8184ca893178682-360p__19106.png"},{"id":10,"thumbnail":"1445615983c92d10f1f3ee907150be1fdb8184ca893178682-360p__19106.png"}]
10-28 09:51:47.249 17872-17872/pishguy.ir.asrebidree E/allVideos: [{"id":12,"thumbnail":"1445615983c92d10f1f3ee907150be1fdb8184ca893178682-360p__19106.png"},{"id":10,"thumbnail":"1445615983c92d10f1f3ee907150be1fdb8184ca893178682-360p__19106.png"}]
Result of server response i'm test it with browser:
[{"id":12,"thumbnail":"1445615983c92d10f1f3ee907150be1fdb8184ca893178682-360p__19106.png"},{"id":10,"thumbnail":"1445615983c92d10f1f3ee907150be1fdb8184ca893178682-360p__19106.png"}]
UNFORTUNATELY this duplicate result is random(NOT duplicate every time)
UPDATE 3:
10-28 13:14:52.322 16129-16129/pishguy.ir.asrebidree E/Test: onCreate called
10-28 13:14:52.513 16129-16129/pishguy.ir.asrebidree E/allVideos: [{"id":12,"thumbnail":"1445615983c92d10f1f3ee907150be1fdb8184ca893178682-360p__19106.png"},{"id":10,"thumbnail":"1445615983c92d10f1f3ee907150be1fdb8184ca893178682-360p__19106.png"}]
10-28 13:14:53.206 16129-16129/pishguy.ir.asrebidree E/allVideos: [{"id":12,"thumbnail":"1445615983c92d10f1f3ee907150be1fdb8184ca893178682-360p__19106.png"},{"id":10,"thumbnail":"1445615983c92d10f1f3ee907150be1fdb8184ca893178682-360p__19106.png"}]
Because I have commented too many lines and I cannot re-produce "duplication behavior" as your current issue, so I post my answer here, hope this helps!
Inside CacheDispatcher class, you will find the following:
if (!entry.refreshNeeded()) {
// Completely unexpired cache hit. Just deliver the response.
mDelivery.postResponse(request, response);
} else {
// Soft-expired cache hit. We can deliver the cached response,
// but we need to also send the request to the network for
// refreshing.
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
// Mark the response as intermediate.
response.intermediate = true;
// Post the intermediate response back to the user and have
// the delivery then forward the request along to the network.
mDelivery.postResponse(request, response, new Runnable() {
#Override
public void run() {
try {
mNetworkQueue.put(request);
} catch (InterruptedException e) {
// Not much we can do about this.
}
}
});
}
IMO, it is possible the softTtl that is causing this duplication behavior.
I suggest that you use the following line to setRetryPolicy for your request:
cacheRequest.setRetryPolicy(new DefaultRetryPolicy(DefaultRetryPolicy.DEFAULT_TIMEOUT_MS * 2, 0, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
// Add the request to the RequestQueue.
queue.add(cacheRequest);
Hi I am using volley jar in my android app to cache the json data for the offline mode.It works perfectly.Here is my code
Cache cache1 = AppController.getInstance().getRequestQueue().getCache();
Entry entry1 = cache1.get(URL);
if (entry1 != null) {
// fetch the data from cache
try {
data2 = new String(entry1.data, "UTF-8");
try {
parseJsonFeed(new JSONObject(data2));
} catch (JSONException e) {
e.printStackTrace();
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} else {
AppController.getInstance().getRequestQueue().getCache().remove(URL);
// making fresh volley request and getting json
JsonObjectRequest jsonReq1 = new JsonObjectRequest(Method.GET,
URL, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
VolleyLog.d(TAG, "Response: " + response.toString());
if (response != null) {
parseJsonFeed(response);
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error:" + error.getMessage());
}
});
// Adding request to volley request queue
AppController.getInstance().addToRequestQueue(jsonReq1);
}
private void parseJsonFeed(JSONObject response) {
try {
feedArray = response.getJSONArray("events");
for (int i = 0; i < feedArray.length(); i++) {
feedObj = (JSONObject) feedArray.get(i);
event_id.add(feedObj.getInt("event_id"));
event_desc.add(feedObj.getString("event_title"));
event_date.add(feedObj.getString("event_date"));
event_place.add(feedObj.getString("event_place"));
event_time.add(feedObj.getString("event_time"));
}
listView.setAdapter(new dataListAdapter(event_date,event_desc,event_place,event_time));
//Log.i("event1111", event.toString());
// Log.i("event2222", event2.toString());
Toast.makeText(getActivity(), "dataa"+event_id, 5000).show();
} catch (JSONException e) {
e.printStackTrace();
}
}
my problem is that I got data.But When I updated json data,the cache data will not update.So how can I change cache data based on json data.Please help me thanks in advance :)
Set the cache header response of your server correctly, I think you need to change the max-age of the header or any custom configuration because Volley looks at the header then stores the response in the cache, here is how it dose:
headerValue = headers.get("Cache-Control");
if (headerValue != null) {
hasCacheControl = true;
String[] tokens = headerValue.split(",");
for (int i = 0; i < tokens.length; i++) {
String token = tokens[i].trim();
if (token.equals("no-cache") || token.equals("no-store")) {
return null;
} else if (token.startsWith("max-age=")) {
try {
maxAge = Long.parseLong(token.substring(8));
} catch (Exception e) {
}
} else if (token.equals("must-revalidate") || token.equals("proxy-revalidate")) {
maxAge = 0;
}
}
}
headerValue = headers.get("Expires");
if (headerValue != null) {
serverExpires = parseDateAsEpoch(headerValue);
}
serverEtag = headers.get("ETag");
// Cache-Control takes precedence over an Expires header, even if both exist and Expires
// is more restrictive.
if (hasCacheControl) {
softExpire = now + maxAge * 1000;
} else if (serverDate > 0 && serverExpires >= serverDate) {
// Default semantic for Expire header in HTTP specification is softExpire.
softExpire = now + (serverExpires - serverDate);
}
Cache.Entry entry = new Cache.Entry();
entry.data = response.data;
entry.etag = serverEtag;
entry.softTtl = softExpire;
entry.ttl = entry.softTtl;
entry.serverDate = serverDate;
entry.responseHeaders = headers;