一、缓存的作用
请求数据的时候,首先进行判断,是否可以从缓存中获取数据,如果满足条件,则直接从缓存中获取数据。否则请求新的数据。这样比没有缓存的情况下,每次都要从服务器请求数据要快,而且,没有网的情况下,也可以浏览已经缓存了的数据,极大的提高了用户的体验。
二、源码解析
源码中用到缓存的地方有:
1 请求数据之前,先判断是否可以从缓存中获取,如果满足条件,则直接从缓存中读取,否则,向服务器请求新的数据。
// 获取缓存的目录
private String getCacheKey() {
return new StringBuilder(getCacheKeyPrefix()).append("_")
.append(mCurrentPage).toString();
}
// 请求数据,判断是否可以从缓存中获取数据
protected void requestData(boolean refresh) {
String key = getCacheKey();
if (isReadCacheData(refresh)) {
readCacheData(key);
} else {
// 取新的数据
sendRequestData();
}
}
//判断是否需要读缓存数据
protected boolean isReadCacheData(boolean refresh) {
String key = getCacheKey();
if (!TDevice.hasInternet()) {
return true;
}
// 第一页若不是主动刷新,且缓存存在,优先取缓存的
if (CacheManager.isExistDataCache(getActivity(), key) && !refresh
&& mCurrentPage == 0) {
return true;
}
// 其他页数的,缓存存在以及还没有失效,优先取缓存的
if (CacheManager.isExistDataCache(getActivity(), key)
&& !CacheManager.isCacheDataFailure(getActivity(), key)
&& mCurrentPage != 0) {
return true;
}
return false;
}
2 对从服务器中获取的最新数据进行保存到缓存的操作
private class SaveCacheTask extends AsyncTask<Void, Void, Void> {
private final WeakReference<Context> mContext;
private final Serializable seri;
private final String key;
private SaveCacheTask(Context context, Serializable seri, String key) {
mContext = new WeakReference<Context>(context);
this.seri = seri;
this.key = key;
}
@Override
protected Void doInBackground(Void... params) {
CacheManager.saveObject(mContext.get(), seri, key);
return null;
}
}
其中saveObject方法实现如下
public static boolean saveObject(Context context, Serializable ser, String file) {
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try {
fos = context.openFileOutput(file, Context.MODE_PRIVATE);
oos = new ObjectOutputStream(fos);
oos.writeObject(ser);
oos.flush();
return true;
要注意的是
(1) data是ListEntity接口的对象,该接口继承了Serializable接口,所以可以直接传参。
(2) key 在这里作为文件路径(缓存目录)。
3 最后,值得一提的是(虽然和Cache没有太大关系),解析完返回的数据后,刷新界面时,对返回数据的处理
protected void executeOnLoadDataSuccess(List<T> data) {
...
//对服务器返回来的数据和已有的数据进行对比,
//如果相同,则将相同的item删掉。最后看data集合的大小
//如果data最后仍然有item ,则更新ListView
for (int i = 0; i < data.size(); i++) {
if (compareTo(mAdapter.getData(), data.get(i))) {
data.remove(i);
i--;
}
}
int adapterState = ListBaseAdapter.STATE_EMPTY_ITEM;
if ((mAdapter.getCount() + data.size()) == 0) {
adapterState = ListBaseAdapter.STATE_EMPTY_ITEM;
} else if (data.size() == 0
|| (data.size() < getPageSize() && mCurrentPage == 0)) {
adapterState = ListBaseAdapter.STATE_NO_MORE;
mAdapter.notifyDataSetChanged();
} else {
adapterState = ListBaseAdapter.STATE_LOAD_MORE;
}
mAdapter.setState(adapterState);
mAdapter.addData(data);
// 判断等于1是因为最后有一项是listview的状态??
if (mAdapter.getCount() == 1) {
if (needShowEmptyNoData()) {
mErrorLayout.setErrorType(EmptyLayout.NODATA);
} else {
mAdapter.setState(ListBaseAdapter.STATE_EMPTY_ITEM);
mAdapter.notifyDataSetChanged();
}
}
}
总结:
1 以上是自己初步从源码中总结出来的一点关于缓存设计的认识和理解,肯定会有很多不周或者不准确的地方,希望能够得到广大博友的指点。自己也会尽量抽空完善的。
2 源码中有些地方,现阶段我也没有完全看懂,但只要不影响大体上的把握,还是可以将自己的理解和整理的东西先分享出来。
作者:项昂之
时间:2015.7.15