zoukankan      html  css  js  c++  java
  • 一种简单粗暴的数据层网络缓存

    先贴出代码:

      1 package com.cache;
      2  
      3 import android.content.Context;
      4 import android.text.TextUtils;
      5 import android.util.Log;
      6  
      7 import com.google.gson.Gson;
      8  
      9 import java.util.ArrayList;
     10 import java.util.List;
     11 import java.util.concurrent.CopyOnWriteArrayList;
     12 import java.util.concurrent.ExecutorService;
     13 import java.util.concurrent.Executors;
     14  
     15 public class CacheHelper {
     16  
     17     private static final String TAG = "CacheHelper";
     18  
     19     private static final String SHARED_PREFERENCES_NAME = "web_content_cache";
     20     private static final String STORE_KEY_XXX = "STORE_KEY_XXX";
     21  
     22     private static final boolean NEED_LIMIT_MAX_CACHE_LENGTH = true;
     23     private static final int MAX_CACHE_LENGTH = 500000;
     24  
     25     private static CacheHelper sInstance;
     26     private ExecutorService mExecutorService;
     27  
     28     public static synchronized CacheHelper instance() {
     29         if (null == sInstance) {
     30             sInstance = new CacheHelper();
     31         }
     32         return sInstance;
     33     }
     34  
     35     private CacheHelper() {
     36         mExecutorService = Executors.newSingleThreadExecutor();
     37  
     38     }
     39  
     40     /**
     41      * 缓存某个场景下的数据。
     42      *
     43      * @param cacheValue
     44      */
     45     public synchronized void cacheXXXList(final List<XXXBean> cacheValue) {
     46         runCache(cacheValue, STORE_KEY_XXX);
     47     }
     48  
     49     /**
     50      * 获取某个场景下的数据缓存,回调在工作线程中执行。(如果有UI操作,请注意需要在post回UI线程执行。)
     51      *
     52      * @param callback
     53      */
     54     public synchronized void getCacheXXXList(final CacheXXXCallback callback) {
     55         if (null == callback) {
     56             return;
     57         }
     58         // 通过某种全局的Utils得到Context,如果没有这种方法,需要在获取实例的时候传入Context
     59         final Context appContext = AppUtils.getContext();
     60         if (null == appContext) {
     61             return;
     62         }
     63         checkThreadPool();
     64         mExecutorService.execute(new Runnable() {
     65             @Override
     66             public void run() {
     67                 // 目前使用SharedPreference存储Json String,可以改成文件等其他方式
     68                 final String cacheStr = appContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
     69                         Context.MODE_PRIVATE).getString(STORE_KEY_XXX, null);
     70                 final List<XXXBean> cacheValue = new CopyOnWriteArrayList<>();
     71                 if (!TextUtils.isEmpty(cacheStr)) {
     72                     final Gson gson = new Gson();
     73                     final List<String> jsons = gson.fromJson(cacheStr, List.class);
     74                     for (String item : jsons) {
     75                         cacheValue.add(gson.fromJson(item, XXXBean.class));
     76                     }
     77                 }
     78                 callback.onGetXXXList(cacheValue);
     79             }
     80         });
     81     }
     82  
     83     public static interface CacheXXXCallback {
     84         public void onGetXXXList(List<XXXBean> cacheValue);
     85     }
     86  
     87     private <T> void runCache(final List<T> list, final String cacheKey) {
     88         // 通过某种全局的Utils得到Context,如果没有这种方法,需要在获取实例的时候传入Context
     89         final Context appContext = AppUtils.getContext();
     90         if (null == appContext) {
     91             return;
     92         }
     93         if (null == list || list.isEmpty()) {
     94             return;
     95         }
     96         final CopyOnWriteArrayList<T> copyList = new CopyOnWriteArrayList<>();
     97         copyList.addAll(list);
     98         if (copyList.isEmpty()) {
     99             return;
    100         }
    101         checkThreadPool();
    102         mExecutorService.execute(new Runnable() {
    103             @Override
    104             public void run() {
    105                 final Gson gson = new Gson();
    106                 final ArrayList<String> jsons = new ArrayList<>();
    107                 for (T t : copyList) {
    108                     jsons.add(gson.toJson(t));
    109                 }
    110                 final String cacheStr = gson.toJson(jsons);
    111                 if (NEED_LIMIT_MAX_CACHE_LENGTH) {
    112                     if (cacheStr.length() > MAX_CACHE_LENGTH) {
    113                         Log.e(TAG, "runCache() : cache value length over max limit.");
    114                         return;
    115                     }
    116                 }
    117                 // 目前使用SharedPreference存储Json String,可以改成文件等其他方式
    118                 appContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
    119                         .edit().putString(cacheKey, cacheStr).commit();
    120             }
    121         });
    122     }
    123  
    124     private void checkThreadPool() {
    125         if (null == mExecutorService || mExecutorService.isShutdown()
    126                 || mExecutorService.isTerminated()) {
    127             mExecutorService = Executors.newSingleThreadExecutor();
    128         }
    129     }
    130 }
    说明几个地方:
    (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在这个场景的使用,稍后有时间会有另一篇文章细聊。存储方式可以替换成文件等,只要将读写操作稍作抽象即可,不影响数据转化的逻辑。
  • 相关阅读:
    CentOS7.6下 MariaDB的MHA 集群搭建(一)
    Mariadb10.4 集群压力测试(一)
    Galera 核心参数详解(一)
    Mariadb10.4+ ERROR 1118 (42000): Row size too large (> 8126). Changing some columns to TEXT or BLOB may help. In current row format, BLOB prefix of 0 bytes is stored inline.
    手动打造一个弹窗程序
    IAT HOOK
    进制的本质
    基于数组越界的缓冲区溢出
    函数调用堆栈图-c语言
    算法之二分查找(上)-c语言实现
  • 原文地址:https://www.cnblogs.com/ganchuanpu/p/7581358.html
Copyright © 2011-2022 走看看