How to clear the volley cache automatically? - android

I want to clear the request queue each 30 minutes for example.
So What is the best way to clear volley cache automatically?
Override methods by extending the volley cache class?
Or build a timer which will clear the cache every times i need?

Google Volley provides 2 ways to clear an item from the Cache:
AppController.getInstance().getRequestQueue().getCache().remove(key);
and
AppController.getInstance().getRequestQueue().getCache().invalidate(key, fullExpire);
Remove means you are removing the actual cached data.
Invalidate means you are just marking the data as invalid. So volley will check with the server whether the data is still valid. The full expire determines whether to use the data before volley has validated it with the server.
To clear cache in each 30 minutes use below code:-
you can use volley's serverDate to get the date for when the response was originally received as
AppController.getInstance().getRequestQueue().getCache().get(url).serverDate
So in your code use getMinutesDifference function as
public static long getMinutesDifference(long timeStart,long timeStop){
long diff = timeStop - timeStart;
long diffMinutes = diff / (60 * 1000);
return diffMinutes;
}
and Call this function in your code as
Calendar calendar = Calendar.getInstance();
long serverDate = AppController.getInstance().getRequestQueue().getCache().get(url).serverDate;
if(getMinutesDifference(serverDate, calendar.getTimeInMillis()) >=30){
AppController.getInstance().getRequestQueue().getCache().invalidate(url, true);
}
It will invalidate the cache,if previous url response >=30 minutes.

Easy way to do that is override onRequestFinished method and clear cache. Or you can run inside the timer after 30 min.
final RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(stringRequest);
requestQueue.addRequestFinishedListener(new RequestQueue.RequestFinishedListener<Object>() {
#Override
public void onRequestFinished(Request<Object> request) {
requestQueue.getCache().clear();
}
});

I was trying to remove bitmap from cache by using remove(key) but it was not working, so I have check url received by putBitmap(String url, Bitmap bitmap). I found url has some prefix like #W0#H#S7http... this is because volley call getCacheKey(String url, int maxWidth, int maxHeight, ScaleType scaleType) for each url. SO if you wants to remove url from cache then you also have to call this function for getting key for url.
String key = mImageLoader.getCacheKey(url, 0, 0, ImageView.ScaleType.CENTER_INSIDE);
mRequestQueue.getCache().remove(key);
Pass 0,0 and ImageView.ScaleType.CENTER_INSIDE if you are using imageLoader.get(String requestUrl,ImageLoader.ImageListener listener) else pass min height and width and scale type you are using.
NOTE getCacheKey() is private function of ImageLoader class so you have to change it to public for using it inside you app.

Related

Picasso - how to get the real image size?

I load an image from URLusing Picasso library. I want to get the real image size, but I can only get the image size in memory:
Picasso.with(this)
.load(imageUrl)
.error(R.drawable.no_image)
.into(photoView, new Callback() {
#Override
public void onSuccess() {
Bitmap bitmap = ((BitmapDrawable)photoView.getDrawable()).getBitmap();
textImageDetail.setText(bitmap.getByteCount());// image size on memory, not actual size of the file
}
#Override
public void onError() { }
});
How to get the size of the loaded image? I think it is stored somewhere in a cache, but I do not know how to access the image file.
Update
Sorry for my bad English, maybe I asked the wrong question. I need to get the image size (128 kb, 2 MB, etc.). NOT the image resolution (800x600, etc.)
You could first get the actual Bitmap image that is getting loaded, and then find the dimensions of that. This has to be run in an asynchronous method like AsyncTask because downloading the image is synchronous. Here is an example:
Bitmap downloadedImage = Picasso.with(this).load(imageUrl).get();
int width = downloadedImage.getWidth();
int height = downloadedImage.getHeight();
If you want to get the actual image size in bytes of the Bitmap, just use
// In bytes
int bitmapSize = downloadedImage.getByteCount();
// In kilobytes
double kbBitmapSize = downloadedImage.getByteCount() / 1000;
Replace the imageUrl with whatever URL you want to use. Hope it helps!
I know this question is old, but I stepped here for an answer and found none.
I found a solution that worked with me using OkHttpClient.
You can fetch the header information only, using OkHttpClient and get the content length without downloading the image.
OkHttpClient httpClient = new OkHttpClient();
Request request = new Request.Builder().url(imageURL).head().build();
Response response = null;
try {
response = httpClient.newCall(request).execute();
String contentLength = response.header("content-length");
int size = Integer.parseInt(contentLength);
} catch (IOException e ) {
if (response!=null) {
response.close();
}
}
Notes:
the above code performs a network call, it should be executed on a background thread.
size is returned in Bytes, you can divide by 1000 if you want it in KB.
this may not work with large files.
Beware, casting to integer could bypass the integer's max value.

Timeout for server request made using "Volley" only on Android not iOS

In one of my application, I am sending request to server using volley provided by Google.
Problem : Timeout and error object is null on onErrorResponse(VolleyError error)
What i have tried so far :
1) First I got null error object so solved it by using below code :
#Override
protected void deliverResponse(String response) {
super.deliverResponse(response);
}
#Override
public void deliverError(VolleyError error) {
super.deliverError(error);
DebugLog.e("deliverResponse", "getNetworkTimeMs : " + error.getNetworkTimeMs());
}
So far I have got that there is timeout happening when I got error object null.
2) Now Application is for Android and iOS and web but timeout happens only for Android.
Volley log for requests :
BasicNetwork.logSlowRequests: HTTP response for request
Edited Note :
Web services develoed at server end is same for all three instances (Android , Web and iOS).
Timeout happens when too many users makes requests to the server.
I have set time out to 2 minutes though volley throws timeout in 30 seconds only sometimes.
I have many answers to change server but as it is not possible so any other solution please.
I also like to add that if i can get more information about when timeout can be possible in volley ?
References I have been gone through :
Optimizing Volley
httpclient-often-times-out-using-wifi-is-going-fine-with-3g
long_xmlhttprequest_ajax_requests_timeout_on_android
Edited :
I have also set retry policy as below:
request.setRetryPolicy(new DefaultRetryPolicy(DefaultRetryPolicy.DEFAULT_TIMEOUT_MS * 48,
0, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
And also i do not want to retry if connection timeout.
How can i make efficient service call that can solve problem for timeout.
Any help will be appriciated.
Thanks.
As i have tried to get solution of this issue for about two months, I did not get any perfect solution. Though I analyze some facts as below :
You can upgrade your server's performance
I have tried making web-service request using HttpURLConnection but still getting same issue over there.
So I think this issue is not specific from volley, but you getting this issue then i would suggest to increase server performance with customizing below RetryPolicy:
int x=2;// retry count
request.setRetryPolicy(new DefaultRetryPolicy(DefaultRetryPolicy.DEFAULT_TIMEOUT_MS * 48,
x, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
Hope it will help.
Suggestions are always welcome :)
Please comment below if you found more proper solution.
Thanks.!
IMHO, you can refer to the following:
Inside BasicNetwork.java, you will find some information such as:
...
private static int SLOW_REQUEST_THRESHOLD_MS = 3000;
...
/**
* Logs requests that took over SLOW_REQUEST_THRESHOLD_MS to complete.
*/
private void logSlowRequests(long requestLifetime, Request<?> request,
byte[] responseContents, StatusLine statusLine) {
if (DEBUG || requestLifetime > SLOW_REQUEST_THRESHOLD_MS) {
VolleyLog.d("HTTP response for request=<%s> [lifetime=%d], [size=%s], " +
"[rc=%d], [retryCount=%s]", request, requestLifetime,
responseContents != null ? responseContents.length : "null",
statusLine.getStatusCode(), request.getRetryPolicy().getCurrentRetryCount());
}
}
...
// if the request is slow, log it.
long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
logSlowRequests(requestLifetime, request, responseContents, statusLine);
...
So, if your project uses Google's volley as a module (not JAR file), you can update BasicNetwork.java, increasing SLOW_REQUEST_THRESHOLD_MS value, perhaps 10000 (ms) or more, for example.
Another option, according to #neuron's answer at the following question:
How to optimize network-queue-take in android Volley? (Volley Google IO 2013)
I think you can try increase the value of NETWORK_THREAD_POOL_SIZE by using the following constructor in your app:
public RequestQueue(Cache cache, Network network, int threadPoolSize) {
this(cache, network, threadPoolSize,
new ExecutorDelivery(new Handler(Looper.getMainLooper()))); }
P/S: if you only want the lines BasicNetwork.logSlowRequests: HTTP response for request not displayed anymore without increasing NETWORK_THREAD_POOL_SIZE, only need to comment (//) the line logSlowRequests... above (when your app uses Google's volley as a module - not jar file, not compile mcxiaoke... in build.gradle file)
Hope it helps!
public class JGet extends Request {
private final Response.Listener listener;
public JGet(final String url, List params,
Response.Listener responseListener) {
super(Request.Method.GET, NetUtils.getUrlWithParams(url, params), new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
NetUtils.dealVolleyError(volleyError, url);
}
});
this.listener = responseListener;
this.setRetryPolicy(new DefaultRetryPolicy(20 * 1000, 0, 1.0f));
LogUtils.e("request-start--->");
LogUtils.e(url);
LogUtils.e(params);
LogUtils.e("request-start--->");
}
}
set timeout time.
Try not using the require statement to connect to your database when sending request to a PHP file using volley.
I've noticed a time-out only when I use something like (require "init.php")
But when I directly put my DB connection information in the same file everything seems to work just fine.
request.setRetryPolicy(new DefaultRetryPolicy( 50000, 5, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT))

Picasso working incorrectly after overriding OkHttpDownloader.load()

I have the following requirements for image download:
ignoring SSL errors (yes I am aware of the risks)
using a session cookie
I tried to adapt Picasso 2.4.0 to do that, below is my approach:
public static Picasso getPicasso(Context context) {
/* an OkHttpClient that ignores SSL errors */
final OkHttpClient client = getUnsafeOkHttpClient();
return new Picasso.Builder(context)
.downloader(new OkHttpDownloader(client) {
#Override
public Response load(Uri uri, boolean localCacheOnly) throws IOException {
final String RESPONSE_SOURCE_ANDROID = "X-Android-Response-Source";
final String RESPONSE_SOURCE_OKHTTP = "OkHttp-Response-Source";
HttpURLConnection connection = openConnection(uri);
connection.setRequestProperty("Cookie", getCookieHandler().
getCookieStore().getCookies().get(0).toString());
connection.setUseCaches(true);
if (localCacheOnly)
connection.setRequestProperty("Cache-Control", "only-if-cached,max-age=" + Integer.MAX_VALUE);
int responseCode = connection.getResponseCode();
if (responseCode == 401)
relogin();
else if (responseCode >= 300) {
connection.disconnect();
throw new ResponseException(responseCode + " " + connection.getResponseMessage());
}
String responseSource = connection.getHeaderField(RESPONSE_SOURCE_OKHTTP);
if (responseSource == null)
responseSource = connection.getHeaderField(RESPONSE_SOURCE_ANDROID);
long contentLength = connection.getHeaderFieldInt("Content-Length", -1);
boolean fromCache = parseResponseSourceHeader(responseSource);
return new Response(connection.getInputStream(), fromCache, contentLength);
}
}).build();
}
The only thing that I changed from the original source is adding a Cookie for the HttpURLConnection. I also copied (unchanged) the parseResponseSourceHeader() method since it has private access.
Note that the approach given here does NOT work (response code 401).
The image loading basically works, but there are major issues:
caching doesn't work (fromCache is always false and Picasso always reloads an image which has already been downloaded)
there's no "Content-Length" header, so contentLength is always -1
though the cache doesn't work, the RAM usage increases when loading next image (into exactly the same or any other ImageView), it seems the Bitmap object stays somewhere in the memory
when used inside the BaseAdapter of a GridView, it seems that Picasso tries to load all (or at least as many as the number of times getView() was called) images at the same time. Those images appear, then the app freezes and closes with the following (OOM?) log:
A/Looper﹕ Could not create wake pipe. errno=24
or
A/Looper﹕ Could not create epoll instance. errno=24
The described issues occur no matter if I use a custom Target of just an ImageView.
It seems I have broken some of Picasso mechanisms by overriding the load() method of the OkHttpDownloader, but I'm not getting what's wrong since I did minimal changes. Any suggestions are appreciated.
In case someone has a similar problem: it was a really lame mistake of mine. I was creating multiple Picasso instances which is complete nonsense. After ensuring the singleton pattern with a helper class that returns a single Picasso instance everything works as intended.

how can one change the default disk cache behavior in volley?

The service I am using to obtain images, like many such sites does not have a cache control header indicating how long the image should be cached. Volley uses an http cache control header by default to decide how long to cache images on disk. How could I override this default behavior and keep such images for a set period of time?
Thanks
I needed to change the default caching strategy to a "cache all" policy, without taking into account the HTTP headers.
You want to cache for a set period of time. There are several ways you can do this, since there are many places in the code that "touch" the network response. I suggest an edit to the HttpHeaderParser (parseCacheHeaders method at line 39):
Cache.Entry entry = new Cache.Entry();
entry.data = response.data;
entry.etag = serverEtag;
entry.softTtl = softExpire;
entry.ttl = now; // **Edited**
entry.serverDate = serverDate;
entry.responseHeaders = headers;
and another to Cache.Entry class:
/** True if the entry is expired. */
public boolean isExpired() {
return this.ttl + GLOBAL_TTL < System.currentTimeMillis();
}
/** True if a refresh is needed from the original data source. */
public boolean refreshNeeded() {
return this.softTtl + GLOBAL_TTL < System.currentTimeMillis();
}
where GLOBAL_TTL is a constant representing the time you want each image to live in the cache.

Volley: How to set up a Cache.Entry

I am using Google's Volley Library as my design for getting network data;
I have set up a RequestQueue
requestQueue = new RequestQueue(new DiskBasedCache(new File(context.getCacheDir(),
DEFAULT_CACHE_DIR)), new BasicNetwork(new
HttpClientStack(AndroidHttpClient.newInstance(userAgent))));
I have also subclassed Request, and have data coming back from the network just fine. My issue is with caching: in parseNetworkResponse() which is overridden in my subclass of Request, when I call
return Response.success(list, HttpHeaderParser.parseCacheHeaders(response));
HttpHeaderParser.parseCacheHeaders(response) returns null since the server is set up for "no caching" in its response header... Regardless I still would like to cache this data for a variable set number of hours (24 hours probably), How can I do this by creating a volley Cache.Entry... It is my understanding that the URL is used as the cache key value (and I would like it to be the URL).
To sum up, since HttpHeaderParser.parseCacheHeaders(response) returns null, I would like to create a new Cache.Entry that is set up for expiring after 24 hours, and the cache key being the URL of the request.
Any thoughts?
Thanks!
I've had the same issue and ended up with this solution:
#Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
// Create a FakeCache that invalidate the data after 24 hour
Cache.Entry mFakeCache = HttpHeaderParser.parseCacheHeaders(response);
mFakeCache.etag = null;
mFakeCache.softTtl = System.currentTimeMillis() + 86400 * 1000;
mFakeCache.ttl = mFakeCache.softTtl;
return Response.success(response.data, mFakeCache);
}

Categories

Resources