转载

Android 框架修炼-自己封装双缓存管理框架库

一、概述

Android开发中,网络请求是很重要的一部分,而缓存网络请求来的图片或者响应结果字符串或者结果流,既可以省流量,同时也可以帮助我们

解决无网或弱网情况下加载情况,当然也可以提升程序性能效率。纵所周知,缓存管理中肯定需要用到内存缓存,这里我们采用LruCache来管理内存的缓存。

LruCahce虽然速度快,但是只是内存级别的缓存,为了实现持久化的缓存,我们还需要文件级别的缓存,也就是说我们要把缓存保存到文件,而文件则是保存

到手机存储或者SD卡存储中,即实现Disk级别的缓存,这里我们借助DiskLruCache这个辅助工具类来实现。顾名思义,这个工具类的作用就是使用Lru算法

来存储信息到Disk上。

二、实例效果图

下面是个简单的实例演示效果图

Android 框架修炼-自己封装双缓存管理框架库

三、缓存管理框架的实现解

1、内存缓存类的实现

该类主要实现内存级别的缓存管理类MemoryCache,使用LruCache来实现,因为无论是内存缓存还是Disk缓存,都需要读写操作,

所以我们先抽象出一个缓存接口类:Cache接口:

 public interface Cache {     String get(final String key);     void put(final String key, final String value);     boolean remove(final String key); } 

然后,我们的内存缓存类MemoryCache需要实现Cache这个接口:

 /**  * 内存缓存类  * Created by caizhiming on 2015/12/4.  */ public class MemoryCache implements Cache {     private LruCache<String, String> mMemoryLruCache;     private EvictedListener mEvictedListener;      public MemoryCache() {         init();     }      public MemoryCache(EvictedListener listener) {         init();         this.mEvictedListener = listener;     }      public void setEvictedListener(EvictedListener listener) {         this.mEvictedListener = listener;     }      public boolean hasEvictedListener() {         return mEvictedListener != null;     }      private void init() {         // 计算可使用的最大内存         final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);         // 取可用内存空间的1/4作为缓存         final int cacheSize = maxMemory / 4;         mMemoryLruCache = new LruCache<String, String>(cacheSize) {             @Override             protected int sizeOf(String key, String value) {                 return value.getBytes().length;             }              @Override             protected void entryRemoved(boolean evicted, String key, String oldValue, String newValue) {                 if (evicted) {                     if (mEvictedListener != null) {                         mEvictedListener.handleEvictEntry(key, oldValue);                     }                 }             }         };     }      @Override     public String get(String key) {         return mMemoryLruCache.get(key);     }      @Override     public void put(String key, String value) {         mMemoryLruCache.put(key, value);     }      @Override     public boolean remove(String key) {         return Boolean.parseBoolean(mMemoryLruCache.remove(key));     }      /**      * called when mMemoryLruCache evict entrys,      * <p/>      * using by CacheManager.Strategy.MEMORY_FIRST      */     public interface EvictedListener {         void handleEvictEntry(String evictKey, String evictValue);     } 

2、文件级别的Disk缓存类实现

接下来我们需要写一个用于Disk缓存管理的类:DiskCache类,该类我们也实现Cache接口,

该类的主要功能也是提供Disk缓存的读取和写入操作管理。

 /**  * Disk磁盘缓存类  * Created by caizhiming on 2015/12/4.  */ public class DiskCache implements Cache{      private DiskLruCache mDiskLruCache = null;     public DiskCache(Context context){         init(context);     }     /**      * 初始化 DiskLruCache      */     public void init(Context context){         try {             File cacheDir = getDiskCacheDir(context, "http_cache");             if (!cacheDir.exists()) {                 cacheDir.mkdirs();             }             Log.v("czm", "cache file=" + cacheDir.getAbsolutePath());             mDiskLruCache = DiskLruCache.open(cacheDir, getAppVersion(context), 1, 10 * 1024 * 1024);         } catch (IOException e) {             e.printStackTrace();         }     }     @Override     public String get(String key) {         String result = null;         try {             DiskLruCache.Snapshot snapShot = mDiskLruCache.get(hashKeyForDisk(key));             if (snapShot != null) {                 result = snapShot.getString(0);                 return result;             }         } catch (IOException e) {             e.printStackTrace();             return null;         }         return result;     }      @Override     public void put(String key, String value) {         DiskLruCache.Editor editor = null;         try {             editor = mDiskLruCache.edit(hashKeyForDisk(key));             if (editor != null) {                 editor.set(0, value);                 editor.commit();             }             mDiskLruCache.flush();         } catch (IOException e) {             e.printStackTrace();         }     }      @Override     public boolean remove(String key) {         try {             return mDiskLruCache.remove(hashKeyForDisk(key));         } catch (IOException e) {             e.printStackTrace();         }         return false;     }      public Bitmap getImageCache(String key){         Bitmap bitmap = null;         try {             DiskLruCache.Snapshot snapShot = mDiskLruCache.get(hashKeyForDisk(key));             if (snapShot != null) {                 InputStream is = snapShot.getInputStream(0);                 bitmap = BitmapFactory.decodeStream(is);                 return bitmap;             }         } catch (IOException e) {             e.printStackTrace();         }         return bitmap;     }     public void putImageCache(final String key){         new Thread(new Runnable() {             @Override             public void run() {                 try {                     DiskLruCache.Editor editor = mDiskLruCache.edit(hashKeyForDisk(key));                     if (editor != null) {                         OutputStream outputStream = editor.newOutputStream(0);                         if (downloadUrlToStream(key, outputStream)) {                             editor.commit();                         } else {                             editor.abort();                         }                     }                     mDiskLruCache.flush();                 } catch (IOException e) {                     e.printStackTrace();                 }             }         }).start();     }     private boolean downloadUrlToStream(String urlString, OutputStream outputStream) {         HttpURLConnection urlConnection = null;         BufferedOutputStream out = null;         BufferedInputStream in = null;         try {             final URL url = new URL(urlString);             urlConnection = (HttpURLConnection) url.openConnection();             in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024);             out = new BufferedOutputStream(outputStream, 8 * 1024);             int b;             while ((b = in.read()) != -1) {                 out.write(b);             }             return true;         } catch (final IOException e) {             e.printStackTrace();         } finally {             if (urlConnection != null) {                 urlConnection.disconnect();             }             CloseUtils.closeCloseable(out);             CloseUtils.closeCloseable(in);         }         return false;     }       public String hashKeyForDisk(String key) {         String cacheKey;         try {             final MessageDigest mDigest = MessageDigest.getInstance("MD5");             mDigest.update(key.getBytes());             cacheKey = bytesToHexString(mDigest.digest());         } catch (NoSuchAlgorithmException e) {             cacheKey = String.valueOf(key.hashCode());         }         return cacheKey;     }      private String bytesToHexString(byte[] bytes) {         StringBuilder sb = new StringBuilder();         for (int i = 0; i < bytes.length; i++) {             String hex = Integer.toHexString(0xFF & bytes[i]);             if (hex.length() == 1) {                 sb.append('0');             }             sb.append(hex);         }         return sb.toString();     }     public File getDiskCacheDir(Context context, String uniqueName) {         String cachePath;         if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())                 || !Environment.isExternalStorageRemovable()) {             cachePath = context.getExternalCacheDir().getPath();         } else {             cachePath = context.getCacheDir().getPath();         }         return new File(cachePath + File.separator + uniqueName);     }      public int getAppVersion(Context context) {         try {             PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);             return info.versionCode;         } catch (PackageManager.NameNotFoundException e) {             e.printStackTrace();         }         return 1;     }   } 

3、搭建封装双缓存管理框架类XCCacheManager

有了上面的内存缓存类MemoryCache和Disk缓存类DiskCache,我们就可以搭建封装真正的缓存管理类XCCacheManager了。

(1) 首先我们采用线程池技术来实现多线程缓存的读写操作

这样可以提高程序的性能,同时能处理任务量比较大的并发读写操作。

  private static XCCacheManager mInstance = null;  private Strategy mStrategy = Strategy.MEMORY_FIRST; //线程池 private ExecutorService mExecutor = null; //内存缓存 private MemoryCache mMemoryCache; //Disk缓存 private DiskCache mDiskCache;  /**      * 初始化 DiskLruCache      */     private void init(Context context) {         mExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());         mDiskCache = new DiskCache(context);         mMemoryCache = new MemoryCache();     } 

(2)其次XCCacheManager管理类采用单例实现

 public static XCCacheManager getInstance(Context context, Strategy strategy) {     if (mInstance == null) {         synchronized (XCCacheManager.class) {             if (mInstance == null) {                 mInstance = new XCCacheManager(context.getApplicationContext(), strategy);             }         }     } else {         mInstance.setStrategy(strategy);     }     return mInstance; } 

(3)缓存策略

这里我们定义了缓存策略,便于适应各种不同业务需求,可以灵活使用不同的策略

 enum Strategy {         MEMORY_ONLY(0), MEMORY_FIRST(1), DISK_ONLY(3);         int id;          Strategy(int id) {             this.id = id;         }     } 

默认采用内存优先MEMORY_FIRST这种策略

(4)根据对应的策略从缓存中读取内容

 /**      * 从缓存中读取value      */     public String readCache(final String key) {         Future<String> ret = mExecutor.submit(new Callable<String>() {             @Override             public String call() throws Exception {                 String result = null;                 switch (mStrategy) {                     case MEMORY_ONLY:                         result = mMemoryCache.get(key);                         break;                     case MEMORY_FIRST:                         result = mMemoryCache.get(key);                         if (result == null) {                             result = mDiskCache.get(key);                         }                         break;                     case DISK_ONLY:                         result = mDiskCache.get(key);                         break;                 }                 return result;             }         });         try {             return ret.get();         } catch (InterruptedException e) {             e.printStackTrace();         } catch (ExecutionException e) {             e.printStackTrace();         }         return null;     } 

(5)将内容写入到缓存中

 /**      * 将value 写入到缓存中      */     public void writeCache(final String key, final String value) {         mExecutor.submit(new Runnable() {             @Override             public void run() {                 switch (mStrategy) {                     case MEMORY_FIRST:                         if (!mMemoryCache.hasEvictedListener()) {                             mMemoryCache.setEvictedListener(new MemoryCache.EvictedListener() {                                 @Override                                 public void handleEvictEntry(String evictKey, String evictValue) {                                     mDiskCache.put(evictKey, evictValue);                                 }                             });                         }                         mMemoryCache.put(key, value);                         break;                     case MEMORY_ONLY:                         if (mMemoryCache.hasEvictedListener())                             mMemoryCache.setEvictedListener(null);                         mMemoryCache.put(key, value);                         break;                     case DISK_ONLY:                         mDiskCache.put(key, value);                         break;                 }             }         });     } 

到此为止,框架的开发到此完成。希望对有需要的人有所帮助。

四、源码下载

源码下载 : http://download.csdn.net/detail/jczmdeveloper/9348031

GitHub地址:https://github.com/jczmdeveloper/XCCacheManager

真题园网 : http://www.zhentiyuan.com

正文到此结束
Loading...