android volley library - show cached result while retrieving - android

I am using Volley and GSON for networking in my app. I have a news feen in the app. I want to show the previously downloaded and cached result right away while downloading the latest content. I have tried accessing the cache using queue.getCache().get(url) but this is always null.
How to properly show cached result while new content is being downloaded?

If it is always null, that means there is no chache for that url. Make sure you did not turned off caching with setShouldCache. Or in http header of response is cache-control: no-cache or max-age=0

Related

Okhttp doesn't return cached response when using Etags

I have a simple use case where a server returns an Etag for a request and that etag is added as a header (i.e. If-None-Match) to all subsequent url requests. The server can respond with a 200 if there is a change in the response or a 304 otherwise. For the latter, it makes sense to reuse the response from cache. But okhttp always returns null as the cached response.
I did some troubleshooting and the response is written to disk internally by okhttp but the CachingStrategy doesn't return it to the CacheInterceptor. Looking closely into the CachingStrategy class, there is documentation specifically stating that the cache won't be used:
/**
* Returns true if the request contains conditions that save the server from sending a response
* that the client has locally. When a request is enqueued with its own conditions, the built-in
* response cache won't be used.
*/
private fun hasConditions(request: Request): Boolean =
request.header("If-Modified-Since") != null || request.header("If-None-Match") != null
}
Is there a way to workaround this behavior and use the cached response instead?
(I have caching enabled as described here and I am using okhttp version 3.10.0)
Also, strangely I am having to manually add the Etag. Okhttp fails to add the etag to subsequent requests on its own.
Edit - correction, Okhttp correctly adds the etag header. I needed to use a network interceptor vs a regular one to see the etag header being added to the subsequent requests
Somewhat related to these issues:
https://github.com/square/okhttp/issues/1400
https://github.com/square/okhttp/issues/831#issuecomment-57900979
Either you do your own caching, or you let OkHttp’s cache do the caching. When you add your own conditions, OkHttp assumes you want full control of the caching and it does not participate in that.

Requests not being made from android app, with max-age set

I have an api that returns an object as the response, and an etag and max age as headers. The response looks like this:
HEADERS:
'x-frame-options': 'SAMEORIGIN',
'x-xss-protection': '1; mode=block',
'x-content-type-options': 'nosniff',
'x-download-options': 'noopen',
'strict-transport-security': 'max-age=15778476000; includeSubDomains',
'access-control-allow-origin': '*',
etag: 'c69148a0489a95058e729bde7fd4bf32bf2077b1cba8d4fcf0c2da6e696fa33e',
'cache-control': 'private,max-age=43200'
BODY:
{
id: 1985,
url: "https://example.com",
...
}
The desired scenario is that an android application makes the request to ask for this data. The Api returns the data, along with an max age of 43200 secs.
If a request is made before 43200 secs pass, the application has the data from the last response cached. The application makes the request nevertheless, the back-end service compiles the response data, uses the request's etag to decide whether the response data has changed. If the data has changed, it returns a 200 http status and the data. Otherwise it returns a 403 status and no data.
The application receives the response. It uses fast networking to handle caching (says my android teammate). If a 200 status code was returned, the data are updated. Otherwise the application keeps the old data.
If a request is made after 43200 secs have passed, the application no longer has the cached response or it's etag. The request is made, the data are considered as 'new' even if nothing has changed in the data, the status code 200 is returned along with max-age header as above.
What actually happens:
For some reason, after the first request is processed and the application receives the data, no request is made until 43200 secs have passed. The android developer says they see that the request is made and 0 bytes are returned, but when I monitor the requests in the server I don't see any made towards this API.
This doesn't make sense, since max-age does not imply that no requests are made. It simply instructs the application to keep the data in the cache for the duration.
Am I missing the idea of how cache, etags and max-age work?
Back-end is built in node js, and uses express for routing.
You've only set the max-age and private directives in the Cache-Control header. The actual behaviour you have described is the correct behaviour since max-age directive has no bearing on forcing the cache to validate responses each time a request is made. For that, you have to add the no-cache directive as well to the Cache-Control header.
The no-cache directives tells the cache to always validate the stored response with the origin server before serving it (i.e., the desired behaviour you have described). Upon revalidation, the stored response will be valid for another 43200 secs (max-age). Without the no-cache directive, the HTTP client is free to make use of cached responses. Which I guess is why your friend said the request was made, but 0 bytes were returned (browsers also show 0 bytes for responses served from the cache). And which is also why you didn't observe any incoming requests to the server.
Have a look at this article from Google for a good overview on HTTP caching:
https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching
If you need in-depth detail on how responses are constructed from caches, have a look at the RFC7234 spec: https://www.rfc-editor.org/rfc/rfc7234#section-4

Handling Http 304 Response In Android

I am using HttpURLConnection for communication with server and using HttpResponseCache for caching, when server respond with 304 (HTTP_NOT_MODIFIED), i got empty body, but according to documentation of HttpURLConnection and HttpResponseCache, in case 304 HttpUrlConnection will fetch the response for the same URL in the cache. While the request for url is cached and i confirmed it. when url is called first time i get proper response (data) while after cached when i called url, Why i am getting empty body (no data).
I fixed the issue by downloading volley library from official google code repository this is the link
https://android.googlesource.com/platform/frameworks/volley/+/master.
Actually the volley source code available at github is customized and cause many issues (github link: https://github.com/mcxiaoke/android-volley), never download from that link.

How to invalidate/force update of cache route at next request with Retrofit and OKHttp?

I'm using Retrofit with OKHttp client for caching responses from a JSON API.
This works nicely.
However, if I take an action on the device which causes the data to update on the server I need a way to 'invalidate' a particular route in order to ensure that next time a request is made for this data, it is fetched from the server again rather than the now outdated cached version.
Currently, I've worked around this by explicitly calling the new route with a "no-cache" flag in the Cache-Control header of the request, but this forces me to download the new data before it is needed, potentially multiple times if multiple actions are taken, just to keep the cache up to date.
Is there a way I can mark a route / method in my retrofit/OKhttp client as cache expired, requiring a mandatory update over the network the next time it's requested?
With retrofit2 and OkHttp3 you can force a new response by adding a Cache-Control header to your API method definition parameters:
#GET("ws/something")
Something getSomething(#Header("Cache-Control") String cacheControl);
and then when calling you either supply null for a (maybe-)cached version or "no-cache" for a live version:
myApi.getSomething(forceRefresh ? "no-cache" : null);
This is now possible in OkHttp by using the Cache.urls() function. As the documentation says:
The iterator supports Iterator.remove(). Removing a URL from the
iterator evicts the corresponding response from the cache. Use this to
evict selected responses.
This was merged into master late December 2014 and seems to be part of these tags (releases): parent-2.4.0-RC1 parent-2.4.0 parent-2.3.0 parent-2.2.0
There isn't an API for this, but there should be one. Please open an OkHttp issue to report this.
It'll probably take a while for us to implement because we'll need to figure out what the best API for this is. Invalidating a single URL is straightforward. Invalidating a range of URLs (say square.com/cash/*) is more difficult because OkHttp's cache is currently organized by URL checksums. There's also ugly edge cases like what happens if the invalidated URL is currently being written to the cache.
To quote the official code sample using urls():
val urlIterator = cache.urls()
while (urlIterator.hasNext()) {
if (urlIterator.next().startsWith("https://www.google.com/")) {
urlIterator.remove()
}
}

403 forbidden with simple Android Picasa album list request

I'm having a terrible time accessing Picasa from Android. After hours of researching, I finally determined that the Google API Java Client library is what I should be using. Several hours later and I divined that I have to use Mercurial and Maven to download and build a sample client so that I can get certain secret libraries that aren't included in the download instructions. And of course the sample client is in no way compatible with and only slightly resembles that in the Picasa Developer's Guide.
So after much trouble I create a simple URL and try to list albums for a user, using code from the sample client:
PicasaUrl url = PicasaUrl.relativeToRoot("feed/api/user/someuser");
UserFeed userFeed = client.executeGetUserFeed(url);
Now the actual URL this creates is something like:
https://picasaweb.google.com/data/feed/api/user/someuser?prettyprint=true
If I put this in my browser, it works fine. In my Android client, however, it gives me an HTTP 403 forbidden error. And no, I can't even run the sample client, because it doesn't give me an APK file. (Plus the source code isn't documented, is written like spaghetti, and uses deprecated methods.)
After turning on protocol-level logging, it turns out that this is the HTTP request being sent:
GET https://picasaweb.google.com/data/feed/api/user/someuser?fields=author/name,entry(#gd:etag,category(#scheme,#term),gphoto:access,gphoto:numphotos,link(#href,#rel),summary,title,updated),link(#href,#rel),openSearch:totalResults&kinds=album&max-results=3&prettyprint=false
Accept-Encoding: gzip
Authorization: GoogleLogin auth=null
User-Agent: MyApp/1.0 Google-HTTP-Java-Client/1.6.0-beta (gzip)
GData-Version: 2
Where in the Sam Hill did all that crap come from? But you know what? The URL still works in my browser. This must be something about the Authorization: header.
After much more pain, I managed to modify the authentication from the sample so that a notification would appear and allow the user to authenticate the account. Now I'm able to list albums.
But I still don't understand: how can I list the public albums without authentication?

Categories

Resources