前言
项目地址
上一篇简单说完Room
创建数据库之后,这一篇主要是说下Room
实现网络缓存
实现
缓存方式
/**
* 仅仅只访问本地缓存,即便本地缓存不存在,也不会发起网络请求
*/
public static final int CACHE_ONLY = 1;
/**
* 先访问缓存,同时发起网络的请求,成功后缓存到本地
*/
public static final int CACHE_FIRST = 2;
/**
* 仅仅只访问服务器,不存任何存储
*/
public static final int NET_ONLY = 3;
/**
* 先访问网络,成功后缓存到本地
*/
public static final int NET_CACHE = 4;
@IntDef({CACHE_ONLY, CACHE_FIRST, NET_CACHE, NET_ONLY})
@Retention(RetentionPolicy.SOURCE)
public @interface CacheStrategy {
}
这里我们暂时定义这4中缓存方式,同时我们在Request
中添加一个这是缓存类型的方法
public R cacheStrategy(@CacheStrategy int cacheStrategy) {
mCacheStrategy = cacheStrategy;
return (R) this;
}
缓存管理
接着我们定义一个缓存管理类CacheManager
,里面定义保存缓存,获取缓存,删除缓存这几个方法
/**
* 缓存管理类
*/
public class CacheManager {
/**
* 反序列,把二进制数据转换成java object对象
*/
private static Object toObject(byte[] data) {
ByteArrayInputStream bais = null;
ObjectInputStream ois = null;
try {
bais = new ByteArrayInputStream(data);
ois = new ObjectInputStream(bais);
return ois.readObject();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (bais != null) {
bais.close();
}
if (ois != null) {
ois.close();
}
} catch (Exception ignore) {
ignore.printStackTrace();
}
}
return null;
}
/**
* 序列化存储数据需要转换成二进制
*/
private static <T> byte[] toByteArray(T body) {
ByteArrayOutputStream baos = null;
ObjectOutputStream oos = null;
try {
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(body);
oos.flush();
return baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (baos != null) {
baos.close();
}
if (oos != null) {
oos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return new byte[0];
}
/**
* 删除缓存
*/
public static <T> void delete(String key, T body) {
Cache cache = new Cache();
cache.key = key;
cache.data = toByteArray(body);
CacheDatabase.get().getCache().deleteItem(cache);
}
/**
* 保存缓存
*/
public static <T> void save(String key, T body) {
Cache cache = new Cache();
cache.key = key;
cache.data = toByteArray(body);
CacheDatabase.get().getCache().insertItem(cache);
}
/**
* 根据key获取缓存
*/
public static Object getCache(String key) {
Cache cache = CacheDatabase.get().getCache().getCache(key);
if (cache != null && cache.data != null) {
return toObject(cache.data);
}
return null;
}
}
这里我们需要在我们的CacheDatabase
类中添加一个获取CacheDao
的方法,我们要借助这个CacheDao
类来实现缓存的增删改查
public abstract CacheDao getCache();
处理网络请求
首先我们在Request
类中的parseResponse
方法中保存缓存
if (mCacheStrategy != NET_ONLY && result.success && result.body != null && result.body instanceof Serializable) {
saveCache(result.body);
}
保存缓存的时候需要一个key
,如果这个key
是个空的话,那么我们就自动生成一个key
,生成规则就是用url
加params
private void saveCache(T body) {
String key = TextUtils.isEmpty(cacheKey) ? generateCacheKey() : cacheKey;
CacheManager.save(key, body);
}
private String generateCacheKey() {
cacheKey = UrlCreator.createUrlFromParams(mUrl, mParams);
return cacheKey;
}
接着就是同步和异步回调内判断是否需要缓存,如果需要,我们就取缓存数据,这里先写一个方法,把缓存数据组装成我们统一返回格式的ApiReponse
private ApiResponse<T> readCache() {
String key = TextUtils.isEmpty(cacheKey) ? generateCacheKey() : cacheKey;
Object cache = CacheManager.getCache(key);
ApiResponse<T> result = new ApiResponse<>();
result.status = 304;
result.message = "缓存获取成功";
result.body = (T) cache;
result.success = true;
return result;
}
然后就是改造下同步和异步的返回
public ApiResponse<T> execute() {
if (mType == null) {
throw new RuntimeException("同步方法,response 返回值 类型必须设置");
}
if (mCacheStrategy == CACHE_ONLY) {
return readCache();
}
ApiResponse<T> result = null;
try {
Response response = getCall().execute();
result = parseResponse(response, null);
} catch (IOException e) {
e.printStackTrace();
if (result == null) {
result = new ApiResponse<>();
result.message = e.getMessage();
}
}
return result;
}
@SuppressLint("RestrictedApi")
public void execute(final JsonCallback callback) {
if (mCacheStrategy != NET_ONLY) {
ArchTaskExecutor.getIOThreadExecutor().execute(new Runnable() {
@Override
public void run() {
ApiResponse<T> response = readCache();
if (callback != null && response.body != null) {
callback.onCacheSuccess(response);
}
}
});
}
if (mCacheStrategy != CACHE_ONLY) {
getCall().enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
ApiResponse<T> result = new ApiResponse<>();
result.message = e.getMessage();
callback.onError(result);
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
ApiResponse<T> result = parseResponse(response, callback);
if (!result.success) {
callback.onError(result);
} else {
callback.onSuccess(result);
}
}
});
}
}