这是我的代码,我在调用api,并通过改造为okhttp定义缓存:
public class DemoPresenter {
DemoView vDemoView;
private Context mContext;
public DemoPresenter(Context mcontext, DemoView vDemoView) {
this.vDemoView = vDemoView;
this.mContext = mcontext;
}
public void callAllProduct() {
if (vDemoView != null) {
vDemoView.showProductProgressBar();
}
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.cache(new Cache(mContext.getCacheDir(), 10 * 1024 * 1024)) // 10 MB
.addInterceptor(new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (BasicUtility.isInternet(mContext)) {
request = request.newBuilder().header("Cache-Control", "public, max-age=" + 60).build();
} else {
request = request.newBuilder().header("Cache-Control", "public, only-if-cached, max-stale=" + 60 * 60 * 24 * 7).build();
}
return chain.proceed(request);
}
})
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("www.xyz.com/data/")
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
AllApi productApiService = retrofit.create(AllApi.class);
Call<ProductData> call = productApiService.getProduct();
try {
call.enqueue(new Callback<ProductData>() {
@Override
public void onResponse(Call<ProductData> call, Response<ProductData> response) {
ArrayList<Product> alproducts = new ArrayList<>();
try {
alproducts = response.body().getProductData();
onSuccess(alproducts);
} catch (Exception e) {
}
}
@Override
public void onFailure(Call<ProductData> call, Throwable t) {
}
});
} catch (Exception e) {
}
}
private void onSuccess(ArrayList<Product> alproducts) {
if (vDemoView != null) {
vDemoView.hideProductProgressBar();
vDemoView.onProductSuccess(alproducts);
}
}
}
现在从我的主要活动开始,我打电话给这个演示者课程:
DemoPresenter mDemoPresenter = new DemoPresenter(getApplicationContext(),this);
mDemoPresenter.callAllProduct();
现在,当我使用互联网连接运行此活动时,它工作正常,但当我断开互联网并再次运行此活动时,它将不会从缓存加载数据。
如果没有互联网,如何从缓存中加载此数据?
答案 0 :(得分:4)
你可以试试这个:
public class DemoPresenter {
DemoView vDemoView;
private Context mContext;
private static final String CACHE_CONTROL = "Cache-Control";
private static final String TAG = DemoPresenter.class.getName();
public DemoPresenter(Context mcontext, DemoView vDemoView) {
this.vDemoView = vDemoView;
this.mContext = mcontext;
}
public void callAllProduct() {
if (vDemoView != null) {
vDemoView.showProductProgressBar();
}
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor( provideOfflineCacheInterceptor() )
.addNetworkInterceptor( provideCacheInterceptor() )
.cache( provideCache() )
.build();
/* OkHttpClient okHttpClient = new OkHttpClient.Builder()
.cache(new Cache(mContext.getCacheDir(), 10 * 1024 * 1024)) // 10 MB
.addInterceptor(new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (BasicUtility.isInternet(mContext)) {
request = request.newBuilder().header("Cache-Control", "public, max-age=" + 60).build();
} else {
request = request.newBuilder().header("Cache-Control", "public, only-if-cached, max-stale=" + 60 * 60 * 24 * 7).build();
}
return chain.proceed(request);
}
})
.build();*/
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("www.xyz.com/data/")
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
AllApi productApiService = retrofit.create(AllApi.class);
Call<ProductData> call = productApiService.getProduct();
try {
call.enqueue(new Callback<ProductData>() {
@Override
public void onResponse(Call<ProductData> call, Response<ProductData> response) {
ArrayList<Product> alproducts = new ArrayList<>();
try {
alproducts = response.body().getProductData();
onSuccess(alproducts);
} catch (Exception e) {
}
}
@Override
public void onFailure(Call<ProductData> call, Throwable t) {
}
});
} catch (Exception e) {
}
}
private void onSuccess(ArrayList<Product> alproducts) {
if (vDemoView != null) {
vDemoView.hideProductProgressBar();
vDemoView.onProductSuccess(alproducts);
}
}
public Interceptor provideOfflineCacheInterceptor () {
return new Interceptor()
{
@Override
public Response intercept (Chain chain) throws IOException
{
Request request = chain.request();
if (BasicUtility.isInternet(mContext))
{
CacheControl cacheControl = new CacheControl.Builder()
.maxStale( 7, TimeUnit.DAYS )
.build();
request = request.newBuilder()
.cacheControl( cacheControl )
.build();
}
return chain.proceed( request );
}
};
}
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( 1, TimeUnit.MINUTES )
.build();
return response.newBuilder()
.header( CACHE_CONTROL, cacheControl.toString() )
.build();
}
};
}
private Cache provideCache ()
{
Cache cache = null;
try
{
cache = new Cache( new File( mContext.getCacheDir(), "http-cache" ),
10 * 1024 * 1024 ); // 10 MB
}
catch (Exception e)
{
Log.e(TAG, "Could not create Cache!");
}
return cache;
}
}
适合我。
答案 1 :(得分:3)
可能出现错误:因为您将所有内容都放在callAllProduct
()中,所以每次创建新的okHttpClient
和新Cache
时,都不会重复使用你的旧Cache
。你在功能上依赖于callAllProduct,callAllProduct依赖于新的okHttpClient,okHttpCient是依赖于新缓存的功能。将okHttpClient
放在callAllProduct
()主体之外会使您在每个callAllProduct调用中依赖于相同的旧okHttpClient。试试这个,即使我也不知道Retrofit内部缓存是如何工作的。如果它仍然无法正常工作,我为我的不工作的想法道歉,但我保证,我会再次帮助你。
这个想法是:每次调用callAllProduct()时,都会使用okHttpClient请求来改进API层。改造层检查它是否已经保存了与您的okHttpClient相关联的数据?每个新的okHttpClient实例意味着每个新的http请求,因此它为缓存数据生成每个新的id。从不使用旧缓存,因为每次使用okHttpClient的新实例时。改造没有看到与您的okHttpRequest实例相关联的任何ID,因此将请求转发到互联网。 Web服务器对数据的响应。现在,Retrofit为该成功的正常HTTP客户端请求的缓存创建新的id。但是当你每次使用新的okHttpClient时,旧的缓存ID从未使用过,因此总是会发生缓存未命中。
以下代码应位于callAllProduct()
正文
int cacheSize = 10 * 1024 * 1024; /* 10 MB. Also try increasing cache size */
public static Cache myCache = new Cache(getCacheDir(), cacheSize);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.cache(myCache) // 10 MB
.addInterceptor(new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (BasicUtility.isInternet(mContext)) {
request = request.newBuilder().header("Cache-Control", "public, max-age=" + 60).build();
} else {
request = request.newBuilder().header("Cache-Control", "public, only-if-cached, max-stale=" + 60 * 60 * 24 * 7).build();
}
return chain.proceed(request);
}
})
.build();
现在,您的callAllProduct()变为如下所示:。这可以保证每次调用callAllProduct()时都使用相同的okHttpClient。
public void callAllProduct() {
if (vDemoView != null) {
vDemoView.showProductProgressBar();
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("www.xyz.com/data/")
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
AllApi productApiService = retrofit.create(AllApi.class);
Call<ProductData> call = productApiService.getProduct();
try {
call.enqueue(new Callback<ProductData>() {
@Override
public void onResponse(Call<ProductData> call, Response<ProductData> response) {
ArrayList<Product> alproducts = new ArrayList<>();
try {
alproducts = response.body().getProductData();
onSuccess(alproducts);
} catch (Exception e) {
}
}
@Override
public void onFailure(Call<ProductData> call, Throwable t) {
}
});
} catch (Exception e) {
}
}
答案 2 :(得分:0)
您的拦截器应检查连接,并相应地设置cacheHeaderValue。在此示例中,它使用方法isNetworkAvailable来执行此操作:
okClient.interceptors().add(
new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
String cacheHeaderValue = isNetworkAvailable(context)
? "public, max-age=2419200"
: "public, only-if-cached, max-stale=2419200" ;
Request request = originalRequest.newBuilder().build();
Response response = chain.proceed(request);
return response.newBuilder()
.removeHeader("Pragma")
.removeHeader("Cache-Control")
.header("Cache-Control", cacheHeaderValue)
.build();
}
}
);
okClient.networkInterceptors().add(
new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
String cacheHeaderValue = isNetworkAvailable(context)
? "public, max-age=2419200"
: "public, only-if-cached, max-stale=2419200" ;
Request request = originalRequest.newBuilder().build();
Response response = chain.proceed(request);
return response.newBuilder()
.removeHeader("Pragma")
.removeHeader("Cache-Control")
.header("Cache-Control", cacheHeaderValue)
.build();
}
}
);
答案 3 :(得分:0)
您需要为OkHttp添加一个脱机缓存拦截器来缓存响应以供离线使用。您还可以缓存数据一分钟,如果请求在一分钟内发送,则使用缓存中的数据。
/**
* Interceptor to cache data and maintain it for four weeks.
*
* If the device is offline, stale (at most four weeks old)
* response is fetched from the cache.
*/
private static class OfflineResponseCacheInterceptor implements Interceptor {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!UtilityMethods.isNetworkAvailable()) {
request = request.newBuilder()
.header("Cache-Control",
"public, only-if-cached, max-stale=" + 2419200)
.build();
}
return chain.proceed(request);
}
}
按照本教程了解有关缓存数据的更多信息 - https://krtkush.github.io/2016/06/01/caching-using-okhttp-part-1.html 此Stack Overflow回答 Can Retrofit with OKHttp use cache data when offline