我正在尝试在互联网连接丢失时执行离线兑现,以便我可以显示缓存中的数据。这是我到目前为止所做的。 我的问题是如何使我的observable返回缓存的数据arraylist而不是只返回错误? 我的服务生成器:
public class ServiceGenerator {
public static final String API_BASE_URL = UrlManager.BASE_URL_API;
private static final String CACHE_CONTROL = "Cache-Control";
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60,TimeUnit.SECONDS)
.readTimeout(60,TimeUnit.SECONDS);
private static Gson gson = new GsonBuilder()
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()));
private static Retrofit retrofit;
public static Gson getGson() {
return gson;
}
public static void setup() {
httpClient.addInterceptor(provideOfflineCacheInterceptor());
httpClient.addInterceptor(new AddCookiesInterceptor()); // VERY VERY IMPORTANT
httpClient.addInterceptor(new ReceivedCookiesInterceptor()); // VERY VERY IMPORTANT
httpClient.addInterceptor( provideHttpLoggingInterceptor() );
httpClient.addNetworkInterceptor(new StethoInterceptor());// Stetho
httpClient.addNetworkInterceptor(provideCacheInterceptor());
httpClient.cache(provideCache());
OkHttpClient client = httpClient.build();
retrofit = builder.client(client).build();
}
public static <S> S createService(Class<S> serviceClass) {
return createService(serviceClass, null);
}
public static <S> S createService(Class<S> serviceClass, final String authToken) {
if (authToken != null) {
httpClient.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization", authToken)
.method(original.method(), original.body());
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
}
return retrofit.create(serviceClass);
}
public static Interceptor provideCacheInterceptor() {
return new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
// re-write response header to force use of cache
CacheControl cacheControl = new CacheControl.Builder()
.maxAge(2, TimeUnit.MINUTES)
.build();
return response.newBuilder()
.header(CACHE_CONTROL, cacheControl.toString())
.build();
}
};
}
public static Interceptor provideOfflineCacheInterceptor() {
return new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!UruzApplication.hasNetwork()) {
CacheControl cacheControl = new CacheControl.Builder()
.maxStale(7, TimeUnit.DAYS)
.build();
request = request.newBuilder()
.cacheControl(cacheControl)
.build();
}
return chain.proceed(request);
}
};
}
private static Cache provideCache() {
Cache cache = null;
try {
cache = new Cache(new File(UruzApplication.getInstance().getCacheDir(), "http-cache"),
10 * 1024 * 1024); // 10 MB
} catch (Exception e) {
Timber.e(e, "Could not create Cache!");
}
return cache;
}
private static HttpLoggingInterceptor provideHttpLoggingInterceptor ()
{
HttpLoggingInterceptor httpLoggingInterceptor =
new HttpLoggingInterceptor( new HttpLoggingInterceptor.Logger()
{
@Override
public void log (String message)
{
Timber.d( message );
}
} );
httpLoggingInterceptor.setLevel( true ? HEADERS : NONE );
return httpLoggingInterceptor;
}
}
我的观察员:
public static Observable<List<WeekDietPlan>>
fetchPackageWeeksDaysDietPlan(int traineeId) {
DietService requestService = ServiceGenerator.createService(DietService.class);
return requestService.getPackageWeekDaysDietPlan(UrlManager.getTraineeDietPackageDetailsUrl(),
traineeId)
.flatMap(new Function<JsonElement, Observable<List<WeekDietPlan>>>() {
@Override
public Observable<List<WeekDietPlan>> apply(JsonElement jsonElement) throws Exception {
JsonObject asJsonObject = jsonElement.getAsJsonObject();
String result = asJsonObject.get(UrlManager.ResultTypes.RESULT).getAsString();
Timber.d(TAG, "result Tag" + result);
if (UrlManager.ResultTypes.isError(result) || UrlManager.ResultTypes.isFailure(result)) {
String errorMessage = asJsonObject.get(UrlManager.ResultTypes.RESULT_ERROR_MESSAGE).getAsString();
return Observable.error(new Exception(errorMessage));
}
if (UrlManager.ResultTypes.isSucess(result)) {
if (!GsonHelper.isNull(asJsonObject.get(UrlManager.ResultTypes.RESULT_DATA)) && asJsonObject.get(UrlManager.ResultTypes.RESULT_DATA).isJsonArray()) {
return Observable.just(WeekDietPlan.PackageDietWeekDaysListParser.fromJsonElement(asJsonObject.getAsJsonArray(UrlManager.ResultTypes.RESULT_DATA)));
} else {
return Observable.error(new Exception("Data is empty"));
}
}
if (UrlManager.ResultTypes.isLogin(result)) {
return Observable.error(new SessionTimeoutException());
}
return Observable.error(new Exception("Unkown Tag"));
}
})
.observeOn(AndroidSchedulers.mainThread());
}
我的api电话:
private void retrievePackageWeekDaysPlan() {
hideConnectionErrorLayout();
if (!swipRefreshLayout_reLoad.isRefreshing()) {
swipRefreshLayout_reLoad.setRefreshing(true);
}
DietNetworkCall.fetchPackageWeeksDaysDietPlan(1).subscribe(new Observer<List<WeekDietPlan>>() {
@Override
public void onSubscribe(Disposable d) {
Timber.d(TAG, "onSubscribe() called with: d = [" + d + "]");
compositeSubscription.add(d);
}
@Override
public void onNext(List<WeekDietPlan> list) {
Timber.d(TAG, "onNext() called with: value = [" + list.size() + "]");
swipRefreshLayout_reLoad.setRefreshing(false);
hideConnectionErrorLayout();
if (list.size() == 0)
{
Toast.makeText(getContext(), R.string.noDietPackageAvailable, Toast.LENGTH_SHORT).show();
}
bindRecyclerData(list);
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
Timber.d(TAG, "onError() called with: e = [" + e + "]");
swipRefreshLayout_reLoad.setRefreshing(false);
if (e instanceof IOException) {
Toast.makeText(getContext(), R.string.connectionError, Toast.LENGTH_SHORT).show();
} else if (e instanceof NullPointerException) {
} else if (e instanceof SessionTimeoutException) {
AuthenticationManager.logOut();
} else {
Toast.makeText(getContext(),
e.getMessage(),
Toast.LENGTH_SHORT).show();
}
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete() called");
}
});
}
答案 0 :(得分:1)
我知道这已经很晚了,并且针对未来的人们。
需要像这样创建一个Network Interceptor
public abstract class NetworkConnectionInterceptor implements Interceptor {
public abstract boolean isInternetAvailable();
public abstract void onInternetUnavailable();
public abstract void onCacheUnavailable();
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!isInternetAvailable()) {
onInternetUnavailable();
request = request.newBuilder().header("Cache-Control",
"public, only-if-cached, max-stale=" + 60 * 60 * 24).build();
Response response = chain.proceed(request);
if (response.cacheResponse() == null) {
onCacheUnavailable();
}
return response;
}
return chain.proceed(request);
}
}
然后使用okhttp构建器添加它。你可以参考这个link。
您应该注意的另一个方法是检查response "Cache-control" header
。它的值必须像"max-age=2592000"
。
答案 1 :(得分:0)
要返回缓存数据而不是错误,您可以使用onErrorReturn运算符:
指示Observable发出一个项目(由指定的项目返回) 函数),而不是在遇到错误时调用onError。
错误时要恢复的不同运营商列表:https://github.com/ReactiveX/RxJava/wiki/Error-Handling-Operators