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

先贴出代码:

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在这个场景的使用,稍后有时间会有另一篇文章细聊。存储方式可以替换成文件等,只要将读写操作稍作抽象即可,不影响数据转化的逻辑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值