In Android okhttpclient not caching public cache-control - android

I am using below code to cache in Android device to collect the response and get from cache till the max age expires. When i use "public" I was able to see the response cached in my application installed folder(/data/data/app_folder).
I tried all below none of them works for "private" but when I change to "public" all my solutions i tried works.
But I need to make it to work for "private". Am I missing something.
Header I will receive "Cache-Control", "private,max-age=120"
Solution 1:
File httpCacheDirectory = new File(context.getCacheDir(), "responses");
HttpResponseCache httpResponseCache = null;
try {
httpResponseCache = new HttpResponseCache(httpCacheDirectory, 10 * 1024 * 1024);
} catch (IOException e) {
Log.e("Retrofit", "Could not create http cache", e);
}
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setResponseCache(httpResponseCache);
Solution 2:
And I am using Retrofit library, an Android client.
Cache cache = new Cache(cacheDirectory, cacheSize);
client = new OkHttpClient();
client.setCache(cache);

Related

Serve cache on timeout in okhttp3

In okhttp3, if my connection times out in CONNECT or READ, is there some way I can get the cache from okhttp? Instead of the connection failing, I want to serve the user from the offline cache in case the request is taking too long.
I did experience a similar issue. I wanted to fallback to cache whenever my request was timing out (I don't mind in which state) or when connection is disrupted, or when there is no connection available. To do this I made an interceptor that would first check for connectivity and after that also catch exceptions when making the request. If there is a timeout then it will throw an exception, after which we fallback to an aggressive caching.
So basically, you first need to set up your okhttp client to use cache and then use an interceptor to use that cache in a better way.
public OkHttpClient getOkHttpClient() {
File cacheFile = new File(context.getCacheDir(), "okHttpCache");
Cache cache = new Cache(cacheFile, CACHE_SIZE);
ConnectivityInterceptor connectivityInterceptor = new ConnectivityInterceptor(networkStateHelper);
OkHttpClient.Builder builder = new OkHttpClient.Builder().cache(cache).addInterceptor(connectivityInterceptor);
return builder.build();
}
After that you can use this simple interceptor to force the usage of the cache. Normally the cache is used when the server responds with 340 which means there are no changes so we can take responses that are cached, but this of course needs an active internet connection. We can however force the cache usage so it will directly take any respond from the cache if possible, which comes in handy when you are offline or when you have timeouts
public class ConnectivityInterceptor implements Interceptor {
// NetworkStateHelper is some class we have that checks if we are online or not.
private final NetworkStateHelper networkStateHelper;
public ConnectivityInterceptor(NetworkStateHelper networkStateHelper) {
this.networkStateHelper = networkStateHelper;
}
#Override
public Response intercept(#NonNull Chain chain) throws IOException {
// You can omit this online check or use your own helper class
if (networkStateHelper.isNotOnline()) {
return getResponseFromCache(chain, request);
}
try {
Response response = chain.proceed(request);
return new Pair<>(request, response);
}
catch (Exception exception) {
Log.w(exception, "Network failure discovered, trying cache fallback");
return getResponseFromCache(chain, request);
}
}
private Response getResponseFromCache(Interceptor.Chain chain,
Request request) throws IOException {
// We just create a new request out of the old one and set cache headers to it with the cache control.
// The CacheControl.FORCE_CACHE is already provided by OkHttp3
request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();
// Now we proceed with the request and OkHttp should automatically fetch the response from cache or return
// a failure if it is not there, some 5xx status code
return chain.proceed(request);
}
}

Retrofit 2 caching - chain of interceptors

I need to implement basic caching of API responses. I've made a little playground project that calls GitHub API and caching was successful (I've used Charles to verify that). However when I transferred this solution to my target project caching didn't work anymore. Could multiple interceptors in the chain be the reason?
Code from playground project (working):
Interceptor (same for target project):
public class CacheControlInterceptor implements Interceptor {
#Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
return response.newBuilder()
.header("Cache-Control", "only-if-cached")
.build();
}
}
Cache and client declaration:
long SIZE_OF_CACHE = 10 * 1024 * 1024; // 10 MB
final Cache cache = new Cache(new File(getCacheDir(), "retrofit_cache"), SIZE_OF_CACHE);
OkHttpClient.Builder client = new OkHttpClient.Builder().cache(cache);
client.networkInterceptors().add(new CacheControlInterceptor());
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/users/")
.addConverterFactory(GsonConverterFactory.create())
.client(client.build())
.build();
Screen from debugging of CacheControlInterceptor:
screen
Code from target project (NOT working):
Cache and client declaration:
private OkHttpClient provideOkHttpClient() {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder okhttpClientBuilder = new OkHttpClient.Builder();
okhttpClientBuilder.connectTimeout(30, TimeUnit.SECONDS);
okhttpClientBuilder.readTimeout(30, TimeUnit.SECONDS);
okhttpClientBuilder.writeTimeout(30, TimeUnit.SECONDS);
okhttpClientBuilder.addInterceptor(loggingInterceptor);
okhttpClientBuilder.addInterceptor(new JwtRenewInterceptor(getUserSession()));
okhttpClientBuilder.addInterceptor(new AutoLoginInterceptor(getUserSession()));
okhttpClientBuilder.addNetworkInterceptor(new CacheControlInterceptor());
long SIZE_OF_CACHE = 10 * 1024 * 1024; // 10 MB
final Cache cache = new Cache(new File(getCacheDir(), "retrofit_cache"), SIZE_OF_CACHE);
okhttpClientBuilder.cache(cache);
return okhttpClientBuilder.build();
}
Screen from debugging of CacheControlInterceptor: screen
If you want apply some headers to all requests using OkHttp cache you should use Application interceptor, not network interceptor. Otherwise, you are not giving cache mechanism a chance to return cached responses.
It's nicely illustrated on OkHttp wiki
So most probably what is happening in your code is that you let Cache to store responses but you never use them since requests going to Cache are missing only-if-cached header.
Try
okhttpClientBuilder.addInterceptor(new CacheControlInterceptor());
Actually the mistake was caused by my poor reasoning about http headers. I thought that method addHeader or header will simply add key Cache-Control and then value only-if-cached. However it adds only value! And since in my target project's API there was no header key Cache-Control (unlike in GitHub API) there was no place for value only-if-cached to be stored.

How to make use of cache data during offine in retrofit?

Am using retrofit 1.9 during offline i need to make use of cache response from server so how to create cache response in retrofit i have heard i can be done with okhttp but can somebody share snippet sample how to make use of cache response?
I am setting cache response like is this right way?
int cacheSize = 10 * 1024 *1024;
File cacheDirectory = new File(mcontext.getCacheDir().getAbsolutePath(), "HttpCache");
Cache cache = new Cache(cacheDirectory, cacheSize);
OkHttpClient client1 = new OkHttpClient();
client1.setCache(cache);
RestAdapter adapter = new RestAdapter.Builder().setEndpoint(url).setClient(new OkClient(client1)).build();
RetrofitRest retro = adapter.create(RetrofitRest.class);

How to use disk cache to cache ParseFile

I'm using Parse and Picasso to load images onto ParseImageViews. Is there anything I'm missing to cache the parse files? My listview seems to be fetching the file from server every time and using the disk cache that comes with Picasso.
I don't see cache-control: max-age parameter in the http responses of downloads of parse files(from amazon s3 where parse stores them)
I have the following code,
final ParseImageView pic = viewHolder.img;
pic.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
ParseFile f = parseObject.getParseFile("image");
Picasso.with(mContext).load(f.getUrl()).into(pic);
Any help would be appreciated. Thanks.
Use OkHttp client as http transport for Picasso and specify disk and memory cache size:
OkHttpClient okHttp = new OkHttpClient();
Cache cache = new Cache(ctx.getCacheDir(), cacheSize);
okHttp.setCache(cache);
// Use OkHttp as downloader
Downloader downloader = new OkHttpDownloader(okHttp);
mPicasso = new Picasso.Builder(getApplicationContext())
.downloader(downloader)).memoryCache(new LruCache(size)).build();
Setup request interceptor (example) for OkHttp client:
// Add Cache-Control to origin response (force cache)
client.networkInterceptors().add(new Interceptor() {
private com.squareup.okhttp.Request request;
private Response response;
private String requestUrl;
#Override
public Response intercept(Chain c) throws IOException {
request = c.request();
response = c.proceed(request);
if (!request.cacheControl().noStore()
&& !response.cacheControl().noStore()) {
requestUrl = request.urlString();
// Do not cache keys or playlists
response = response
.newBuilder()
.header("Cache-Control","public, max-age=42000").build();
}
return response;
}
});

How to get data on OkHttp response code 304?

I read that a response with code 304 (Not Modified) should have no body. In that case, does OkHttp get the body from the cache, or shall we get it explicitely, i.e.
if reponseCode == 304:
body = <getDataFromCache>
In the latter case, how to get the data from the cache?
OkHttpClient client = new OkHttpClient();
File cacheDirectory = new File(context.getCacheDir(), "responses");
Cache cache = null;
try {
cache = new Cache(cacheDirectory, 10 * 1024 * 1024); // 10M
client.setCache(cache);
} catch (IOException e) {
Log.e("AbstractFeedIntentService", "Could not create http cache", e);
}
Request.Builder requestBuilder = new Request.Builder();
requestBuilder.url(url);
Request request = requestBuilder.build();
Call call = client.newCall(request);
Response response = call.execute();
// if code==304, does the response contain the data from the cache. If not, how to get it?
OkHttp will return data from its response cache.

Categories

Resources