如何从包含android中API响应的缓存中获取改造缓存数据
Posted
技术标签:
【中文标题】如何从包含android中API响应的缓存中获取改造缓存数据【英文标题】:How to fetch retrofit cache data from cache memory which contains API response in android 【发布时间】:2017-05-09 16:39:54 【问题描述】:该类包含用于调用 API 的 APIClient 实例,但在获取缓存时存在一个问题。我想在设备未连接到网络时从缓存中获取数据。
private static Retrofit retrofit = null;
private static final String CACHE_CONTROL = "Cache-Control";
public static Retrofit getClient(Context context)
if (retrofit==null)
retrofit = new Retrofit.Builder()
.baseUrl(URLS.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(provideOkHttpClient(context))
.build();
return retrofit;
/**
* Add Client for adding Authentication headers.
* @return Retrofit
*/
public static Retrofit getAthenticationClient()
if (retrofit==null)
retrofit = new Retrofit.Builder()
.baseUrl(URLS.BASE_URL)
.client(ApiIntercepters.AddAuthenticationHeader())
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit;
public static OkHttpClient provideOkHttpClient(Context context)
return new OkHttpClient.Builder()
.addNetworkInterceptor(provideCacheInterceptor())
.cache( provideCache(context))
.build();
private static Cache provideCache (Context context)
Cache cache = null;
try
//setup cache
File httpCacheDirectory = new File(context.getCacheDir(), "responses");
int cacheSize = 10 * 1024 * 1024; // 10 MiB
cache = new Cache(httpCacheDirectory, cacheSize);
catch (Exception e)
Log.e( "Injector :-> ", "Could not create Cache!" );
return cache;
public static Interceptor provideCacheInterceptor ()
return new Interceptor()
@Override
public Response intercept (Chain chain) throws IOException
Response originalResponse = chain.proceed(chain.request());
if (RetrofitDemoApp.hasNetwork())
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 * 28; // tolerate 4-weeks stale
return originalResponse.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.build();
;
【问题讨论】:
为什么在检索数据时不保存数据以备后用? 您能告诉我如何在改造中使用高速缓存保存数据吗?我是 Retrofit 缓存管理的新手。 看看这里***.com/questions/23429046/… 谢谢!!!我正在获得解决方案,但在获得响应时,我在离线模式下收到 504 错误:@Override public void onResponse(Call这是一个我也想要的解决方案,我实现了它,它可以正常工作,将数据存储在缓存中,然后获取数据。
检查下面的代码
CacheManager.java
public class CacheManager
private Context context;
private static final String TAG = CacheManager.class.getSimpleName();
public CacheManager(Context context)
this.context = context;
public void writeJson(Object object, Type type, String fileName)
File file = new File(context.getCacheDir(), fileName);
OutputStream outputStream = null;
Gson gson = new GsonBuilder().enableComplexMapKeySerialization().setPrettyPrinting().create();
try
outputStream = new FileOutputStream(file);
BufferedWriter bufferedWriter;
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream,
StandardCharsets.UTF_8));
else
bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));
gson.toJson(object, type, bufferedWriter);
bufferedWriter.close();
catch (FileNotFoundException e)
Log.i(TAG,""+e);
catch (IOException e)
Log.i(TAG,""+e);
finally
if (outputStream != null)
try
outputStream.flush();
outputStream.close();
catch (IOException e)
Log.i(TAG,""+e);
public Object readJson(Type type, String fileName)
Object jsonData = null;
File file = new File(context.getCacheDir(), fileName);
InputStream inputStream = null;
Gson gson = new GsonBuilder().enableComplexMapKeySerialization().setPrettyPrinting().create();
try
inputStream = new FileInputStream(file);
InputStreamReader streamReader;
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
streamReader = new InputStreamReader(inputStream,
StandardCharsets.UTF_8);
else
streamReader = new InputStreamReader(inputStream, "UTF-8");
jsonData = gson.fromJson(streamReader, type);
streamReader.close();
catch (FileNotFoundException e)
e.printStackTrace();
if (DEBUG) Log.e(TAG, "loadJson, FileNotFoundException e: '" + e + "'");
catch (IOException e)
e.printStackTrace();
if (DEBUG) Log.e(TAG, "loadJson, IOException e: '" + e + "'");
finally
if (inputStream != null)
try
inputStream.close();
catch (IOException e)
if (DEBUG) Log.e(TAG, "loadJson, finally, e: '" + e + "'");
return jsonData;
用于在缓存中存储和获取数据
MainActivity.java
if (checkInternetConnection(getContext()))
progressBar.setVisibility(View.VISIBLE);
Api mApiService = RetrofitClient.getClient(Api.BASE_URL).create(Api.class);
Call<ApiModel> call = mApiService.getCountry();
call.enqueue(new Callback<ApiModel>()
@Override
public void onResponse(Call<ApiModel> call, Response<ApiModel> response)
countryList = response.body();
countryListData = countryList.data;
CacheManager cacheManager = new CacheManager(MainActivity.this);
//store data in cache
Type type = new TypeToken<ApiModel>()
.getType();
cacheManager.writeJson(response.body(), type, "latest.json");
adapter = new MyListAdapter(getApplicationContext(), countryListData);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(adapter);
progressBar.setVisibility(View.GONE);
Log.i(TAG, "onResponse: SuccessFull");
@Override
public void onFailure(Call<ApiModel> call, Throwable t)
Toast.makeText(getApplicationContext(), "An error has occurred", Toast.LENGTH_LONG).show();
//api failed to return data due to network problem or something else, display data from cache file
Type type = new TypeToken<ApiModel>()
.getType();
countryList = (ApiModel) cacheManager.readJson(type, "latest.json");
Log.i(TAG, "onFailure: " + t);
progressBar.setVisibility(View.GONE);
);
else
//No internet connected then fetch data if exists
Type type = new TypeToken<ApiModel>()
.getType();
countryList = (ApiModel) cacheManager.readJson(type, "latest.json");
System.out.println("cacheData" + countryList.data.get(1));
if (countryList != null)
countryListData = countryList.data;
adapter = new MyListAdapter(getApplicationContext(), countryListData);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(adapter);
【讨论】:
以上是关于如何从包含android中API响应的缓存中获取改造缓存数据的主要内容,如果未能解决你的问题,请参考以下文章
如何从服务器获取和设置 android 中的 API(从服务器获取 int 值)?如何绑定和实现这个