2015-12-16 9 views
16

Próbuję buforować niektóre odpowiedzi w mojej aplikacji przy użyciu Retrofit 2.0, ale brakuje mi czegoś.Buforowanie HTTP z Retrofit 2.0.x

Zainstalowałem plik buforowania następująco:

private static File httpCacheDir; 
private static Cache cache; 
try { 
    httpCacheDir = new File(getApplicationContext().getCacheDir(), "http"); 
    httpCacheDir.setReadable(true); 
    long httpCacheSize = 10 * 1024 * 1024; // 10 MiB 
    HttpResponseCache.install(httpCacheDir, httpCacheSize); 
    cache = new Cache(httpCacheDir, httpCacheSize); 
    Log.i("HTTP Caching", "HTTP response cache installation success"); 
} catch (IOException e) { 
    Log.i("HTTP Caching", "HTTP response cache installation failed:" + e); 
} 

public static Cache getCache() { 
     return cache; 
    } 

który tworzy plik w /data/user/0/<PackageNmae>/cache/http , a następnie przygotował przechwytywania sieci w następujący sposób:

public class CachingControlInterceptor implements Interceptor { 
    @Override 
    public Response intercept(Chain chain) throws IOException { 
     Request request = chain.request(); 

     // Add Cache Control only for GET methods 
     if (request.method().equals("GET")) { 
      if (ConnectivityUtil.checkConnectivity(getContext())) { 
       // 1 day 
       request.newBuilder() 
        .header("Cache-Control", "only-if-cached") 
        .build(); 
      } else { 
       // 4 weeks stale 
       request.newBuilder() 
        .header("Cache-Control", "public, max-stale=2419200") 
        .build(); 
      } 
     } 

     Response originalResponse = chain.proceed(chain.request()); 
     return originalResponse.newBuilder() 
      .header("Cache-Control", "max-age=86400") 
      .build(); 
    } 
} 

mój Retrofit i OkHttpClient instancja:

OkHttpClient client = new OkHttpClient(); 
client.setCache(getCache()); 
client.interceptors().add(new MainInterceptor()); 
client.interceptors().add(new LoggingInceptor()); 
client.networkInterceptors().add(new CachingControlInterceptor()); 
Retrofit restAdapter = new Retrofit.Builder() 
     .client(client) 
     .baseUrl(Constants.BASE_URL) 
     .addConverterFactory(GsonConverterFactory.create(gson)) 
     .build(); 

productsService = restAdapter.create(ProductsService.class); 

gdzie ProductsService.class zawiera:

@Headers("Cache-Control: max-age=86400") 
@GET("categories/") 
Call<PagedResponse<Category>> listCategories(); 

i

Call<PagedResponse<Category>> call = getRestClient().getProductsService().listCategories(); 
call.enqueue(new GenericCallback<PagedResponse<Category>>() { 
     // whatever 
     // GenericCallback<T> implements Callback<T> 
    } 
}); 

Pytanie brzmi: jak to zrobić dostępu buforowane odpowiedzi kiedy urządzenie jest w trybie offline?

Nagłówek odpowiedzi backend to:

Allow → GET, HEAD, OPTIONS 
Cache-Control → max-age=86400, must-revalidate 
Connection → keep-alive 
Content-Encoding → gzip 
Content-Language → en 
Content-Type → application/json; charset=utf-8 
Date → Thu, 17 Dec 2015 09:42:49 GMT 
Server → nginx 
Transfer-Encoding → chunked 
Vary → Accept-Encoding, Cookie, Accept-Language 
X-Frame-Options → SAMEORIGIN 
x-content-type-options → nosniff 
x-xss-protection → 1; mode=block 

Odpowiedz

13

Wreszcie otrzymuję odpowiedź.

Network Interceptor powinna być następująca:

public class CachingControlInterceptor implements Interceptor { 
@Override 
public Response intercept(Chain chain) throws IOException { 
    Request request = chain.request(); 

    // Add Cache Control only for GET methods 
    if (request.method().equals("GET")) { 
     if (ConnectivityUtil.checkConnectivity(YaootaApplication.getContext())) { 
      // 1 day 
      request = request.newBuilder() 
        .header("Cache-Control", "only-if-cached") 
        .build(); 
     } else { 
      // 4 weeks stale 
      request = request.newBuilder() 
        .header("Cache-Control", "public, max-stale=2419200") 
        .build(); 
     } 
    } 

    Response originalResponse = chain.proceed(request); 
    return originalResponse.newBuilder() 
     .header("Cache-Control", "max-age=600") 
     .build(); 
} 
} 

następnie zainstalowanie pliku cache jest takie proste

long SIZE_OF_CACHE = 10 * 1024 * 1024; // 10 MiB 
Cache cache = new Cache(new File(context.getCacheDir(), "http"), SIZE_OF_CACHE); 
OkHttpClient client = new OkHttpClient(); 
client.cache(cache); 
client.networkInterceptors().add(new CachingControlInterceptor()); 
+0

metoda setCache okhttp3.OkHttpClient jest niedostępna client.setCache (pamięć podręczna); – toidv

+5

Klient OkHttpClient = new OkHttpClient.Builder(). Cache (cache) .networkInterceptor (nowy CachingControlInterceptor()). Build(); –

+0

@Amr Barakat Chcę zaimplementować buforowanie także dla metody Post, czy to możliwe? w jaki sposób? –

8

W swojej CachingControlInterceptor, tworzyć nowe żądania, ale nigdy rzeczywiście z nich korzystać. Zadzwoń pod numer newBuilder i zignoruj ​​wynik, więc modyfikacja nagłówka nigdy nie jest wysyłana w żadnym miejscu. Spróbuj przypisać te wartości do request, a następnie zamiast wywoływać proceed na chain.request() zadzwoń pod numer request.

public class CachingControlInterceptor implements Interceptor { 
    @Override 
    public Response intercept(Chain chain) throws IOException { 
     Request request = chain.request(); 

     // Add Cache Control only for GET methods 
     if (request.method().equals("GET")) { 
      if (ConnectivityUtil.checkConnectivity(getContext())) { 
       // 1 day 
       request = request.newBuilder() 
        .header("Cache-Control", "only-if-cached") 
        .build(); 
      } else { 
       // 4 weeks stale 
       request = request.newBuilder() 
        .header("Cache-Control", "public, max-stale=2419200") 
        .build(); 
      } 
     } 

     Response originalResponse = chain.proceed(request); 
     return originalResponse.newBuilder() 
      .header("Cache-Control", "max-age=600") 
      .build(); 
    } 
} 
+0

czy możesz wyjaśnić, co robi ostatnia część? return originalResponse.newBuilder() .header ("Cache-Control", "max-age = 600") .build(); –

+0

Myślałem, że jeśli dodasz nagłówek '(" Cache-Control "," tylko-jeśli-cache ")', pobierze go tylko wtedy, gdy jest buforowany. W przeciwnym razie nie będzie nawet kłopotać się z żądaniem sieci. – yoavgray

+0

@iagreen jest to możliwe z metodą "Post"? –

-3
OkHttpClient client = new OkHttpClient.Builder().cache(cache).build(); 
+4

Proszę podać informacje lub wyjaśnienie rozwiązania. – DeepSpace

4

można też spróbować:

public class CachingInterceptor implements Interceptor { 
    @Override 
    public okhttp3.Response intercept(Chain chain) throws IOException { 
     Request request = chain.request(); 

     request = new Request.Builder() 
       .cacheControl(new CacheControl.Builder() 
         .maxAge(1, TimeUnit.DAYS) 
         .minFresh(4, TimeUnit.HOURS) 
         .maxStale(8, TimeUnit.HOURS) 
         .build()) 
       .url(request.url()) 
       .build(); 


     return chain.proceed(request); 
    } 
} 
0

I wreszcie odkrył rozwiązanie, nad którym pracowaliśmy mi w modernizowanych 2.x oraz 3.x OkHttp

musiałem wdrożyć dwa przechwytujących, jeden z nich jest odpowiedzialny przepisać żądanie nagłówkia druga przepisać nagłówki odpowiedzi .

  1. Po pierwsze, pamiętaj o usunięciu starej pamięci podręcznej. (root explorer/data/data/com.yourapp/cache

  2. instancję budowniczy klient:

    OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder() 
        .cache(cache) 
        .addInterceptor(new RewriteRequestInterceptor()) 
        .addNetworkInterceptor(new RewriteResponseCacheControlInterceptor()) 
    
  3. Tworzenie RewriteRequestInterceptor

    public class RewriteRequestInterceptor implements Interceptor { 
        @Override 
        public Response intercept(Chain chain) throws IOException { 
         int maxStale = 60 * 60 * 24 * 5; 
         Request request; 
         if (NetworkUtils.isNetworkAvailable()) { 
          request = chain.request(); 
         } else { 
          request = chain.request().newBuilder().header("Cache-Control", "max-stale=" + maxStale).build(); 
         } 
         return chain.proceed(request); 
        } 
    } 
    
  4. Tworzenie RewriteResponseCacheControlInterceptor

    public class RewriteResponseCacheControlInterceptor implements Interceptor { 
        @Override 
        public Response intercept(Chain chain) throws IOException { 
         int maxStale = 60 * 60 * 24 * 5; 
         Response originalResponse = chain.proceed(chain.request()); 
         return originalResponse.newBuilder().header("Cache-Control", "public, max-age=120, max-stale=" + maxStale).build(); 
        } 
    } 
    

Ważne jest, aby dodać obiekt ResponseCacheControlInterceptor jako przechwytywacz sieciowy, a także obiekt przepisującyRequestInterceptor jako przechwytywacz (tak jak zrobiłem to w drugim kroku).

Powiązane problemy