2016-07-24 34 views
2

Aus der Antwort für diese Frage Can Retrofit with OKHttp use cache data when offline konnte ich mit dieser Frage kommen, aber der Code scheint nicht zu cachen. Was könnte ich falsch machen?Retrofit 2 & OKHttp 3 Caching-Antwort funktioniert nicht in meinem Fall

Das ist mein okhttp Client

long SIZE_OF_CACHE = 10 * 1024 * 1024; // 10 MB 
    Cache cache = new Cache(getDirectory(), SIZE_OF_CACHE); 
    if (cache == null) { 
     Toast.makeText(AppController.getInstance().getApplicationContext(), "could n0t set cache", Toast.LENGTH_SHORT).show(); 
    } 

    client = new OkHttpClient 
      .Builder() 
      .addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR) 
      .cache(cache) 
      .build(); 

mein Netzwerk Interceptor hinzufügen ist wie folgt:

private static final Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() { 
     @Override 
     public Response intercept(Chain chain) throws IOException { 
      Response originalResponse = chain.proceed(chain.request()); 
      if (isConnected()) { 
       int maxAge = 60; // read from cache for 1 minute 
       return originalResponse.newBuilder() 
         .header("Cache-Control", "public, max-age=" + maxAge) 
         .build(); 
      } else { 
       int maxStale = 60 * 60 * 24; // tolerate 1-day stale 
       return originalResponse.newBuilder() 
         .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale) 
         .build(); 
      } 
     } 
    }; 

Am Zugabe wie folgt nachrüsten:

public static Retrofit getClient() { 
     createCacheForOkHTTP(); 
     if (retrofit == null) { 
      retrofit = new Retrofit.Builder() 
        .client(client) 
        .baseUrl(BASE_URL) 
        .addConverterFactory(GsonConverterFactory.create()) 
        .build(); 
     } 
     return retrofit; 
    } 

// in meiner Aktivität hinzufügen :

ApiInterface apiService = 
       ApiClient.getClient().create(ApiInterface.class); 

     Call<MovieResponse> call = apiService.getPopularMoviesDetails(ApiKey, page); 
     call.enqueue(new Callback<MovieResponse>() { 
      @Override 
      public void onResponse(Call<MovieResponse> call, Response<MovieResponse> response) { 
       progressBar.setVisibility(View.GONE); 
       mErrorView.setVisibility(View.GONE); 
       if (response.isSuccessful()) { 
        movies = response.body().getResults(); 
        movieAdapter.setMovieList(movies); 
        mRecyclerView.setAdapter(movieAdapter); 
       } else { 
        Toast.makeText(getActivity(), "header" + response.headers() + "code" + response.code() + "errorbody" + response.errorBody() + "errorbody" + response.message(), Toast.LENGTH_SHORT).show(); 
       } 

      } 

      @Override 
      public void onFailure(Call<MovieResponse> call, Throwable t) { 
       progressBar.setVisibility(View.GONE); 
       // Log error here since request failed 
       Log.e(TAG, t.toString()); 
       mErrorView.setVisibility(View.VISIBLE); 

      } 
     }); 

// Schnittstelle

@GET("movie/popular") 
    Call<MovieResponse> getPopularMoviesDetails(@Query("api_key") String apiKey, @Query("page") int page); 

Antwort

1

Nicht sicher, ob Sie bereits dieses Problem zu beheben. Ich habe eine tolle/kurze Lösung gefunden, hoffe es hilft.

Ich erstelle eine CacheControlInterceptor. Dies hat 24 Stunden Cache, wenn Sie offline sind und Ihre Antwort weniger als 24 Stunden alt ist, erhalten Sie die Cache-Antwort.

public class CacheControlInterceptor implements Interceptor { 

    private static final String CACHE_CONTROL_HEADER = "Cache-Control"; 
    private static final String MAX_AGE_HEADER_VALUE = "public, max-age="; 
    private static final String MAX_STALE_HEADER_VALUE = "public, only-if-cached, max-stale="; 

    // Specifies the maximum amount of time a resource will be considered fresh. 
    private static final int MAX_AGE = 60; 

    // Indicates that the client is willing to accept a response that has exceeded its expiration time. 
    private static final int MAX_STALE = 60 * 60 * 24; // 24 hours cache. 

    @Override 
    public Response intercept(Chain chain) throws IOException { 

     Request request = chain.request(); 

     if (WatchItApplication.hasNetwork()) { 
      request = request.newBuilder() 
        .header(CACHE_CONTROL_HEADER, MAX_AGE_HEADER_VALUE + MAX_AGE).build(); 
     } else { 
      request = request.newBuilder() 
        .header(CACHE_CONTROL_HEADER, MAX_STALE_HEADER_VALUE + MAX_STALE).build(); 
     } 

     return chain.proceed(request); 
    } 
} 

Auf dieser Methode erzeuge ich die OKHttpCliente. Wie Sie bemerken, füge ich den CacheControlInterceptor und den Cache hinzu.

private OkHttpClient createDefaultOkHttpClient() { 
     HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); 
     interceptor.setLevel(HttpLoggingInterceptor.Level.BASIC); 

     return new OkHttpClient.Builder() 
       .retryOnConnectionFailure(true) 
       .connectTimeout(TIMEOUT_MILLIS, TIMEOUT_UNIT) 
       .readTimeout(TIMEOUT_MILLIS, TIMEOUT_UNIT) 
       .writeTimeout(TIMEOUT_MILLIS, TIMEOUT_UNIT) 
       .addNetworkInterceptor(new HeaderInterceptor()) 
       .cache(new Cache(WatchItApplication.getInstance().getCacheDir(), 10 * 1024 * 1024)) 
       .addInterceptor(new CacheControlInterceptor()) 
       .addInterceptor(interceptor) 
       .build(); 
    } 

Schließlich Retrofit:

retrofit = new Retrofit.Builder() 
       .baseUrl(BASE_URL) 
       .client(createDefaultOkHttpClient()) 
       .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 
       .addConverterFactory(GsonConverterFactory.create(gson)) 
       .build(); 

Lassen Sie mich wissen, ob das funktioniert.

2

Sie sollten keine Antworten vom Server neu schreiben, um das Caching zu erleichtern. Es ist besser, die Administratoren Ihres Servers zu bitten, Cache-Header einzubinden, wenn sie Antworten liefern. Auf diese Weise funktioniert der Cache für alle Clients - nicht nur für OkHttp.

Das heißt, Sie sind ein Erwachsener und Sie haben Anspruch auf technische Abkürzungen, um zu vermeiden, mit Ihrem Server-Team zu sprechen.

Zuerst müssen Sie Ihren Code ändern, um sowohl einen network interceptor als auch einen Anwendungsabfanger zu verwenden. Warum zwei? Nun, wenn Sie Anfragen in den Cache stellen, sind die Netzwerk-Interzeptoren noch nicht gestartet. Und wenn Sie Antworten in den Cache schreiben, sind die Anwendungsabfangprogramme noch nicht gestartet.

Ihre Anwendung Abfangjäger werden Ihre Anfrage Header umschreiben diese zu schließen, wenn Sie den Cache bevorzugen, und den Cache zu ermöglichen veraltete Antworten zu dienen:

Cache-Control: only-if-cached, max-stale=86400 

Ihr Netzwerk Interceptor wird Ihre Server-Response-Header umschreiben diese enthalten so dass alle Antworten für 24 Stunden zwischengespeichert werden:

Cache-Control: max-age=86400 
0

konnte ich die issue.This lösen ist, wie ich es tat.

private static OkHttpClient getCacheClient(final Context context) { 
    Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() { 
     @Override 
     public okhttp3.Response intercept(Chain chain) throws IOException { 
      okhttp3.Response originalResponse = chain.proceed(chain.request()); 
      if (isConnected()) { 
       // Internet available; read from cache for 0 day 
       // Why? Reduce server load, better UX 
       int maxAge = 0; 
       return originalResponse.newBuilder() 
         .header("Cache-Control", "public, max-age=" + maxAge) 
         .build(); 
      } else { 
       // No internet; tolerate cached data for 1 week 
       int maxStale = 60 * 60 * 24 * 7; 
       return originalResponse.newBuilder() 
         .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale) 
         .build(); 
      } 
     } 
    }; 

    File httpCacheDirectory = new File(context.getCacheDir(), "cachedir"); 
    int size = 5 * 1024 * 1024; 
    Cache cache = new Cache(httpCacheDirectory, size); 

    return new OkHttpClient.Builder() 
      .addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR) 
      .cache(cache) 
      .build(); 
} 

Und Nutzung:

public static Retrofit getClient(final Context context) { 

    if (retrofit == null) { 
     retrofit = new Retrofit.Builder() 
       .client(getCacheClient(context)) 
       .baseUrl(BASE_URL) 
       .addConverterFactory(GsonConverterFactory.create()) 
       .build(); 
    } 
    return retrofit; 
}