I won’t say much about the power of Retrofit+OkHttp. Students who don’t know yet can go to Baidu by themselves. This article mainly talks about how to use Retrofit+OkHttp to implement a simple cache strategy:
That is, when we request data in a network environment, if there is no cache or the cache expires, we go to the server to get the data and save the new cache. If there is a cache and it has not expired, we will use the cache directly. When we request data in an internet-free environment, the cache will be used directly if it does not expire. If the cache expires, it will not be used. We need to reconnect to the network to obtain server data.
Cache processing is still very necessary. It effectively reduces server load, reduces latency and improves user experience, and also facilitates users to use the APP even without a network.
I have always had a doubt before. Since Retrofit is already an encapsulation of OkHttp, why do I keep saying that Retrofit+OkHttp should be used together? Later I learned that one of the important functions of OKHttp is to configure some network requests, such as connection timeout, read timeout, and some cache configurations.
1. Add dependencies
compile '.retrofit2:retrofit:2.1.0' compile '.retrofit2:converter-gson:2.1.0' compile '.okhttp3:okhttp:3.4.1' compile '.okhttp3:logging-interceptor:3.4.1'
2. Configure OkHttpClient (set cache path and cache file size)
File httpCacheDirectory = new File((), "HttpCache");//For the convenience of the file, it is directly placed in HttpCache in the root directory of the SD card, usually placed in ()int cacheSize = 10 * 1024 * 1024;//Set the cache file size to 10MCache cache = new Cache(httpCacheDirectory, cacheSize); httpClient = new () .connectTimeout(10, )//Set connection timeout .readTimeout(10, )//Read timeout .writeTimeout(10, )//Write timeout .addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)//Add a custom cache interceptor (explained later), note that you need to use .addNetworkInterceptor here. .cache(cache)//Add cache in .build();
3. Configure Retrofit
retrofit = new () .baseUrl(baseUrl) .client(httpClient)//Add OkHttpClient in .addConverterFactory(()) .build();
IV. Write an interceptor
We know that the cache of Retrofit+OkHttp is actually mainly implemented through interceptors, so the main effort is also in the interceptors.
static Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = (); //Many sample codes on the Internet make judgments on the request before the request request. In fact, there is no need to judge, and the cache is automatically accessed without the network.// if(!().isConnected()){ // request = () // .cacheControl(CacheControl.FORCE_CACHE)// Access only cache// .build(); // } Response response = (request); if (().isConnected()) { int maxAge = 60;//The cache invalidation time, unit is seconds return () .removeHeader("Pragma")//Clear header information, because if the server does not support it, some interference information will be returned. If it is not cleared, the following will not take effect. .header("Cache-Control", "public ,max-age=" + maxAge) .build(); } else { //This code is invalid// int maxStale = 60 * 60 * 24 * 28; // When there is no network, set the timeout to 4 weeks// return () // .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale) // .removeHeader("Pragma") // .build(); } return response; } };
At this point, we can actually achieve the cache effect we mentioned at the beginning.
However, the cache time for each interface set above is the same. For example, I want to make the cached data invalidation time of different interfaces different, and some interfaces even do not cache data. What should I do? Actually it's very simple
First of all, we only need to add the @Headers parameter in front of the interface (max-age represents the cache time, unit is seconds. In the example, the cache failure time is 60s. You can set the time you want by yourself). If you do not set the @Headers parameter, you will not cache it.
@Headers("Cache-Control:public ,max-age=60") @GET("")//Shop InformationCall<RestaurantInfoModel> getRestaurantInfo(@Query("userId") String userId,@Query("businessId") String businessId);
At the same time, our cache interceptor also needs to make simple modifications (remove the previous comment code)
static Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = (); Response response = (request); if (().isConnected()) { //Get header information String cacheControl =().toString(); return () .removeHeader("Pragma")//Clear header information, because if the server does not support it, some interference information will be returned. If it is not cleared, the following will not take effect. .header("Cache-Control", cacheControl) .build(); } return response; } };
*Notice:
1. Only the interface requested by Get is cached, but not the interface requested by Post is cached.
You need to use .addNetworkInterceptor to add a cache interceptor, you cannot use .addInterceptor, and you do not need to use both at the same time.
3. This method does not require any operation on the server side. It does not have other cache policies on the server side. If the server side has its own cache policy code, it should be modified accordingly to adapt to the server side.
Attach all codes:
/** * Simple encapsulated Retroit initialization class */ public class initRetrofit { private static String baseUrl = "http://202.171.212.154:8080/hh/"; private static OkHttpClient httpClient; private static Retrofit retrofit; public static Retrofit initRetrofit() { //Cache path and size File httpCacheDirectory = new File((), "HttpCache"); int cacheSize = 10 * 1024 * 1024; Cache cache = new Cache(httpCacheDirectory, cacheSize); //Log Interceptor HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); (); httpClient = new () .connectTimeout(10, )//Set connection timeout .readTimeout(10, )//Read timeout .writeTimeout(10, )//Write timeout .addInterceptor(interceptor)//Add a log interceptor .addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)//Add a cache interceptor .cache(cache)//Add cache in .build(); retrofit = new () .baseUrl(baseUrl) .client(httpClient) .addConverterFactory(()) .build(); return retrofit; } public static RetrofitAPI getService() { return initRetrofit().create(); } // // Cache interceptor, different caches for different interfaces// static Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() { // @Override // public Response intercept(Chain chain) throws IOException { // // Request request = (); // Response response = (request); // // if (().isConnected()) { // String cacheControl =().toString(); // return () // .removeHeader("Pragma")//Clear header information, because if the server does not support it, some interference information will be returned. If it is not cleared, the following will not take effect.// .header("Cache-Control", cacheControl) // .build(); // } // return response; // } // }; //Cache interceptor, unified cache for 60s static Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = (); Response response = (request); if (().isConnected()) { int maxAge = 60*60*24*2;//The cache invalidation time, unit is seconds return () .removeHeader("Pragma")//Clear header information, because if the server does not support it, some interference information will be returned. If it is not cleared, the following will not take effect. .header("Cache-Control", "public ,max-age=" + maxAge) .build(); } return response; } }; }
The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.