安卓日記——可快取的知乎日報

飢渴計科極客傑鏗發表於2016-07-12

我很久之前一直在想文字的快取到底是怎麼弄的呢,難道存在資料庫?
最近發現okhttp可以設定快取和攔截器,配合retrofit用起來實在是太方便了

雖說retrofit的是基於okhttp的,但新增攔截器的做法,使okhttpclient更像是一個配置的容器,攔截器和快取設定就相當於配置

之前看過我
安卓日記——手把手教你做知乎日報
安卓日記——MVP重構知乎日報

都已經掌握了知乎日報的基本做法和mvp重構法

現在要新增一個功能,將知乎日報的內容快取起來,無網路時還能翻看,就像朋友圈一樣

這次新增功能是基於上次MVP知乎日報的

1.首先匯入包

我們要將原來的retrofit換為retorfit2,所以要將原來retorfit的包換成

    compile 'com.squareup.retrofit2:retrofit:2.0.2'
    compile 'com.squareup.retrofit2:converter-gson:2.0.2'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'

我們等一下要用到okhttp3,所以要加上

compile 'com.squareup.okhttp3:logging-interceptor:3.1.2'

新增完後可能原來的程式碼會報錯,找不到retrofit的包
這時只需刪掉頭部import retrofit的部分,重新匯入retrofit2的就行了

2.新增許可權

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

3.給retrofit新增攔截器和快取

新增也十分簡單
只需在ServiceFactory中新增就行了
新增後程式碼如下

public class ServiceFactory {
    public static <T> T createRetrofitService(Class<T> clazz, String baseUrl, final Context context){
        //設定快取目錄
        File cacheFile = new File(context.getExternalCacheDir(), "jkgeekjk");
        OkHttpClient.Builder builder =new OkHttpClient.Builder();
        //快取大小50MB
        Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);
        Interceptor cacheInterceptor = new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                //如果網路沒有連線則設為強制快取
                if (!NetUtils.isConnected(context)){
                    request = request.newBuilder()
                            .cacheControl(CacheControl.FORCE_CACHE)
                            .build();
                }
                Response response = chain.proceed(request);
                if (NetUtils.isConnected(context)) {
                    int maxAge = 0;
                    // 有網路時 設定快取超時時間0個小時
                    response.newBuilder()
                            .header("Cache-Control", "public, max-age=" + maxAge)
                            .removeHeader("Pragma")// 清除頭資訊,因為伺服器如果不支援,會返回一些干擾資訊,不清除下面無法生效
                            .build();
                } else {
                    // 無網路時,設定超時為4周
                    int maxStale = 60 * 60 * 24 * 28;
                    response.newBuilder()
                            .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                            .removeHeader("Pragma")
                            .build();
                }
                return response;
            }
        };
        //
        builder.cache(cache).addInterceptor(cacheInterceptor);
        OkHttpClient client=builder.build();

        final Retrofit retrofit=new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .client(client)
                .build();
        T service =retrofit.create(clazz);
        return service;
    }
}

4.判斷網路是否連通的工具類

public class NetUtils
{
    private NetUtils()
    {
        throw new UnsupportedOperationException("cannot be instantiated");
    }

    /**
     * 判斷網路是否連線
     *
     * @param context
     * @return
     */
    public static boolean isConnected(Context context)
    {

        ConnectivityManager connectivity = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);

        if (null != connectivity)
        {

            NetworkInfo info = connectivity.getActiveNetworkInfo();
            if (null != info && info.isConnected())
            {
                if (info.getState() == NetworkInfo.State.CONNECTED)
                {
                    return true;
                }
            }
        }
        return false;
    }

}

然後一個可快取的知乎日報就做好了

原始碼下載

相關文章