您的位置:首页 > 理论基础 > 计算机网络

一种简单粗暴的数据层网络缓存(二)实现方案

2016-11-07 19:56 260 查看
先贴出代码:

package com.cache;

import android.content.Context;
import android.text.TextUtils;
import android.util.Log;

import com.google.gson.Gson;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CacheHelper {

private static final String TAG = "CacheHelper";

private static final String SHARED_PREFERENCES_NAME = "web_content_cache";
private static final String STORE_KEY_XXX = "STORE_KEY_XXX";

private static final boolean NEED_LIMIT_MAX_CACHE_LENGTH = true;
private static final int MAX_CACHE_LENGTH = 500000;

private static CacheHelper sInstance;
private ExecutorService mExecutorService;

public static synchronized CacheHelper instance() {
if (null == sInstance) {
sInstance = new CacheHelper();
}
return sInstance;
}

private CacheHelper() {
mExecutorService = Executors.newSingleThreadExecutor();

}

/**
* 缓存某个场景下的数据。
*
* @param cacheValue
*/
public synchronized void cacheXXXList(final List<XXXBean> cacheValue) {
runCache(cacheValue, STORE_KEY_XXX);
}

/**
* 获取某个场景下的数据缓存,回调在工作线程中执行。(如果有UI操作,请注意需要在post回UI线程执行。)
*
* @param callback
*/
public synchronized void getCacheXXXList(final CacheXXXCallback callback) {
if (null == callback) {
return;
}
// 通过某种全局的Utils得到Context,如果没有这种方法,需要在获取实例的时候传入Context
final Context appContext = AppUtils.getContext();
if (null == appContext) {
return;
}
checkThreadPool();
mExecutorService.execute(new Runnable() {
@Override
public void run() {
// 目前使用SharedPreference存储Json String,可以改成文件等其他方式
final String cacheStr = appContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
Context.MODE_PRIVATE).getString(STORE_KEY_XXX, null);
final List<XXXBean> cacheValue = new CopyOnWriteArrayList<>();
if (!TextUtils.isEmpty(cacheStr)) {
final Gson gson = new Gson();
final List<String> jsons = gson.fromJson(cacheStr, List.class);
for (String item : jsons) {
cacheValue.add(gson.fromJson(item, XXXBean.class));
}
}
callback.onGetXXXList(cacheValue);
}
});
}

public static interface CacheXXXCallback {
public void onGetXXXList(List<XXXBean> cacheValue);
}

private <T> void runCache(final List<T> list, final String cacheKey) {
// 通过某种全局的Utils得到Context,如果没有这种方法,需要在获取实例的时候传入Context
final Context appContext = AppUtils.getContext();
if (null == appContext) {
return;
}
if (null == list || list.isEmpty()) {
return;
}
final CopyOnWriteArrayList<T> copyList = new CopyOnWriteArrayList<>();
copyList.addAll(list);
if (copyList.isEmpty()) {
return;
}
checkThreadPool();
mExecutorService.execute(new Runnable() {
@Override
public void run() {
final Gson gson = new Gson();
final ArrayList<String> jsons = new ArrayList<>();
for (T t : copyList) {
jsons.add(gson.toJson(t));
}
final String cacheStr = gson.toJson(jsons);
if (NEED_LIMIT_MAX_CACHE_LENGTH) {
if (cacheStr.length() > MAX_CACHE_LENGTH) {
Log.e(TAG, "runCache() : cache value length over max limit.");
return;
}
}
// 目前使用SharedPreference存储Json String,可以改成文件等其他方式
appContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
.edit().putString(cacheKey, cacheStr).commit();
}
});
}

private void checkThreadPool() {
if (null == mExecutorService || mExecutorService.isShutdown()
|| mExecutorService.isTerminated()) {
mExecutorService = Executors.newSingleThreadExecutor();
}
}
}

说明几个地方:
(1)在helper类内部用线程池实现了异步。使用异步的原因第一,存储Json String的方式有可能是文件,有可能是SharedPreference,涉及到IO;第二,可能会频繁调用写cache和读cache,异步化可以降低调用线程的压力,另外在单一的工作线程(单一线程的线程池)中顺序执行读、写,实现同步。
(2)通过测试发现,对于数据实体对象,Gson无法将对象的List直接转成Json字符串,但大多数的应用场景都是List,所以采用先将List中的每一个对象转成Json String,组成一个List<String>,然后再将List<String>转成一个Json String,存储。在读缓存的时候,是以上过程的逆过程,先将存储的Json String转成List<String>,然后将List中的每一个String转成一个数据实体对象。
(3)存储的方式目前使用的是SharedPreference。关于SharedPreference在这个场景的使用,稍后有时间会有另一篇文章细聊。存储方式可以替换成文件等,只要将读写操作稍作抽象即可,不影响数据转化的逻辑。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: