android - Retrofit 2 + rx - 如何在 android 中检查响应来源(网络、缓存或两者)?

标签 android rx-java retrofit2 rx-android okhttp

我正在连接到webService,如下所示:

private CompositeDisposable mCompositeDisposable;
 PublicApi publicApi = retrofitApi.getClient("https://xxx.xxx.xxx", context, 1);
        mCompositeDisposable.add(publicApi.language("getLanguages")
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .subscribe(language -> responseLanguage(language, resultListener), language -> errorLanguage(language, resultListener)));

得到如下结果:

private void responseLanguage(Languages languages, RemoteDataSource.ResultListener<Languages> resultListener) {
}

private void errorLanguage(Throwable error, RemoteDataSource.ResultListener<Languages> resultListener) {
    error.printStackTrace();
}

如何检查响应来源,如以下链接:

Retrofit 2 — Check Response Origin (Network, Cache, or Both)

我需要知道结果是来自缓存还是网络服务(在线),因为我正在缓存结果,如下所示:

public class RetrofitApi {
    private static PublicApi retrofit = null;
    private Context context;


    public PublicApi getClient(String url, Context context, Integer value) {
        OkHttpClient okHttpClient;
        this.context = context;
        try {
            // Create a trust manager that does not validate certificate chains
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };

            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            // Create an ssl socket factory with our all-trusting manager
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });

            if (value == 1) {
                //For get Log see D/OkHttp
                HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
                // set your desired log level
                logging.setLevel(HttpLoggingInterceptor.Level.HEADERS);
                File httpCacheDirectory = new File(this.context.getCacheDir(), "responses");
                int cacheSize = 10 * 1024 * 1024; // 10 MiB
                Cache cache = new Cache(httpCacheDirectory, cacheSize);

                if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                    okHttpClient = builder.
                            addNetworkInterceptor(REWRITE_RESPONSE_INTERCEPTOR)
                            .addInterceptor(OFFLINE_INTERCEPTOR)
                            .addInterceptor(logging)
                            .cache(cache)
                            .build();
                } else {
                    okHttpClient = new OkHttpClient.Builder()
                            .addNetworkInterceptor(REWRITE_RESPONSE_INTERCEPTOR)
                            .addInterceptor(OFFLINE_INTERCEPTOR)
                            .addInterceptor(logging)
                            .cache(cache)
                            .build();
                }


            } else {
                okHttpClient = builder.build();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }


        retrofit = new Retrofit.Builder()
                .baseUrl(url)
                .client(okHttpClient)
                //.client(httpClient.build())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build().create(PublicApi.class);

        return retrofit;
    }

    private Interceptor REWRITE_RESPONSE_INTERCEPTOR = chain -> {
        Response originalResponse = chain.proceed(chain.request());
        String cacheControl = originalResponse.header("Cache-Control");

        if (cacheControl == null || cacheControl.contains("no-store") || cacheControl.contains("no-cache") ||
                cacheControl.contains("must-revalidate") || cacheControl.contains("max-age=0")) {
            return originalResponse.newBuilder()
                    .removeHeader("Pragma")
                    .header("Cache-Control", "public, max-age=" + 60)
                    .build();
        } else {
            return originalResponse;
        }
    };


    private Interceptor OFFLINE_INTERCEPTOR = chain -> {
        Request request = chain.request();
        if (!Utils.isNetworkAvailable(context)) {
            int maxStale = 60 * 60 * 24 * 2; // tolerate 2-days stale
            request = request.newBuilder()
                    .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                    .build();
        }

        return chain.proceed(request);
    };
}

最佳答案

您可以将预期的对象包装在 PublicApi与 Retrofit 的接口(interface) Response 对象,当使用 RxJava 和 RxJavaCallAdapaterFactory 时:

@GET
Response<Languages> language(String param);

Response是请求响应的包装器,其中包含有关响应的各种信息,这与您提到的 article 中的对象相同,在非 RxJava 中返回 enqueue()使用 Call<> 时的请求.
然后在订阅者中您将获得 Response<Languages>对象,您将能够使用 response.raw().cacheResponse() 检查它是否是缓存对象/response.raw().networkResponse()如上述教程中所述。

关于android - Retrofit 2 + rx - 如何在 android 中检查响应来源(网络、缓存或两者)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45387848/

相关文章:

android - 区分 list 中的隐式广播接收器与显式广播接收器

android - 如何将 TextView 置于中心?

android - OkHttp 上的不平衡进入/退出

rx-java - 使用 rx 链接时 Android 测试失败

java - Retrofit2 将数组作为 HashMap 发送会产生不同的格式

Android (Java) - 带有 Retrofit 2.1.0 的 POST(带标题)

android - 将图片从url保存到sdcard

android - ADT 在 DDMS 中获取 BufferOverflowException

java.lang.NoClassDefFoundError : io. reactivex.Flowable

android - 无法在 Retrofit 2.0 中解析具有两种不同数据类型的 json