Search code examples
androidretrofit2cache-controloffline-caching

Offline mode with Retrofit 2 Cache-Control


I am working on a android app which has requirement of offline mode , I am using retrofit 2 with cache control , but facing problem that cache files are not getting created and only file is created in that folder is named journal.I am posting my ApiClient.java file code here.

public class ApiClient {

public static final String BASE_URL = "http://www.something.com/";
private static Retrofit retrofit = null;
private static APIInterfaces apiInterface;
private  static Context mcontext=getApplicationContext();


static Interceptor OFFLINE_INTERCEPTOR = new Interceptor() {
    @Override
    public okhttp3.Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        if (!isConnected()) {
            int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks stale
            request = request.newBuilder()
                    .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                    .build();
        }

        return chain.proceed(request);
    }
};


static Interceptor ONLINE_INTERCEPTOR = new Interceptor() {
    @Override
    public okhttp3.Response intercept(Chain chain) throws IOException {
        okhttp3.Response response = chain.proceed(chain.request());
        int maxAge = 60; // read from cache
        return response.newBuilder()
                .header("Cache-Control", "public, max-age=" + maxAge)
                .build();
    }
};



protected static Retrofit getClient() {
    if (retrofit == null) {

        createFolder();
        Gson gson = new GsonBuilder()
                .setLenient()
                .create();


        OkHttpClient okHttpClient = new OkHttpClient
                .Builder()
                .cache(new Cache(new File(Environment.getExternalStorageDirectory() + File.separator + "something"), 10 * 1024 * 1024)) // 10 MB
                .addInterceptor(OFFLINE_INTERCEPTOR)
                .addNetworkInterceptor(ONLINE_INTERCEPTOR)
                .build();

        retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL).client(okHttpClient)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .build();
    }
    return retrofit;
}


public static APIInterfaces getApiInterface() {
    if (apiInterface == null)
        apiInterface = ApiClient.getClient().create(APIInterfaces.class);
    return apiInterface;
}



private static boolean isConnected() {
    try {
        android.net.ConnectivityManager e = (android.net.ConnectivityManager) mcontext.getSystemService(
                Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetwork = e.getActiveNetworkInfo();
        return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
    } catch (Exception e) {
        Log.w(TAG, e.toString());
    }

    return false;
}

public  static boolean isStoragePermissionGranted() {
    if (Build.VERSION.SDK_INT >= 23) {
        if (mcontext.checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                == PackageManager.PERMISSION_GRANTED) {
            return true;
        } else {
            ActivityCompat.requestPermissions((Activity) mcontext,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
            return false;
        }
    }
    else { //permission is automatically granted on sdk<23 upon installation
        return true;
    }
}



private static void createFolder() {
    if (isStoragePermissionGranted()) {
        File folder = new File(Environment.getExternalStorageDirectory() + File.separator + "Something");

        if (!folder.exists()) {
            folder.mkdir();
        }
    }
}

}

Can anyone please explain what is problem with above code.


Solution

  • When you use interceptors to change headers it does not make any adjustments before CacheStrategy.isCacheable() is called.

    Try changing interceptors() with networkInterceptors() call.

    Have a look here: https://github.com/square/okhttp/wiki/Interceptors

    Also, you can't cache POST requests with OkHttp’s cache. You’ll need to store them using some other mechanism, see this

    Other mechanisms:

    There are several methods, one can be storing the online results to a local database and retrieve it from there if offline which most people do, the second option is to override OKHTTP but that will be costly for a mobile device in terms of performance over benefit, the third one is obviously converting your POST API structure to GET

    But, have a look here it contains a blog article too, which will help you.