1. 程式人生 > >(MyStudy:一)三級快取:首先是記憶體-檔案(外存)-網路三級快取機制。

(MyStudy:一)三級快取:首先是記憶體-檔案(外存)-網路三級快取機制。

三級快取:首先是記憶體-檔案(外存)-網路三級快取機制。
三級快取
首先:
框架需要一個接入方法NGImageloadHelper.Java:

/**
 * 圖片載入框架使用幫助類
 * Created by nangua on 2016/7/8.
 */
public class NGImageloadHelper {
    /**
     * 處理圖片
     * @param view
     * @param url
     */
    public static void displayImage(ImageView view,
                                    String url) {
        NGDownloadImage.getInstance().addTask(url,
                view);
        NGDownloadImage.getInstance().doTask();
    }
}

然後,使用具體的快取實現類NGDownloadImage:
首先判斷傳入的url對應圖片是否在內外存中,如果不在,則新增進執行緒池的自定義任務佇列中,這裡傳入的任務是自定義的實現Callble介面的任務TaskWithResult,在帶回調引數的執行方法call中執行一個自定義的handler—-TaskHandler,該TaskHandler的handlerMessage方法內部根據傳入的圖片型別判斷,執行相應的下載方法(通過HttpUrlConnection實現)並移除taskmap中對應的圖片任務。

/**
 * 圖片載入類
 * Created by nangua on 2016/7/8.
 */
public class NGDownloadImage { private ExecutorService executorService; //執行緒池服務 private NGImageMemoryCache imageMemoryCache; private NGImageFileCache imageFileCache; private NGDownloadImageMode downloadImageMode; //圖片例項 private Map<String, View> taskMap; private static NGDownloadImage instance; //自身私有化例項
private int POOL_SIZE = 5;//執行緒池自定義大小 private NGDownloadImage() { final int cpuNums = Runtime.getRuntime().availableProcessors();//cpu數 executorService = Executors.newFixedThreadPool(cpuNums * POOL_SIZE); imageMemoryCache = new NGImageMemoryCache(); imageFileCache = new NGImageFileCache(); downloadImageMode = new NGDownloadImageMode(); taskMap = new HashMap<>(); } //獲得唯一例項 public static synchronized NGDownloadImage getInstance() { if (instance == null) { instance = new NGDownloadImage(); } return instance; } /** * 新增任務 * * @param url * @param img */ public void addTask(String url, ImageView img) { addTask(null, url, img, null); } public void addTask(Object parent, String url, View img, NGImageCallback callback) { if (img == null) { return; } if (TextUtils.isEmpty(url)) { return; } if (callback != null) { downloadImageMode = new NGDownloadImageMode(); downloadImageMode.setCallback(callback); downloadImageMode.setParent(parent); downloadImageMode.setImgUrl(url); img.setTag(downloadImageMode); } else { img.setTag(url); } //生成Bitmap final Bitmap bitmap = imageMemoryCache.getBitmapFromCache(url); //如果快取裡有 if (bitmap != null) { //如果有實現的回撥介面,則用回撥介面載入圖片 if (callback != null) { callback.imageLoaded(parent, img, bitmap, downloadImageMode); } else { //如果沒有,則直接設定該圖片為bitmap if (img instanceof ImageView) ((ImageView) img).setImageBitmap(bitmap); } } else { //如果快取沒有這個圖片 if (taskMap != null) { //新增到任務集合裡去 synchronized (taskMap) { final String mapKey = Integer.toString(img.hashCode()); if (!taskMap.containsKey(mapKey)) { taskMap.put(mapKey, img); } } } } } public void doTask() { if (taskMap == null) { return; } else { synchronized (taskMap) { Collection<View> collection = taskMap.values(); for (View view : collection) { if (view != null) { Object object = view.getTag(); String url = ""; if (object instanceof NGDownloadImageMode) { url = ((NGDownloadImageMode) object).getImgUrl(); } else { url = (String) object; } if (!TextUtils.isEmpty(url)) { loadImage(url, view); } } } } } } private void loadImage(final String url, final View img) { loadImage(url, img, null); } private void loadImage(final String url, final View img, NGImageCallback callback) { executorService.submit(new TaskWithResult(new TaskHandler(url, img, callback), url)); } private class TaskWithResult implements Callable<String> { private String url; private Handler handler; public TaskWithResult(Handler handler, String url) { this.url = url; this.handler = handler; } @Override public String call() throws Exception { // TODO Auto-generated method stub final Message message = handler.obtainMessage(0, getBitmap(url)); handler.sendMessage(message); return url; } } private class TaskHandler extends Handler { private String url; private View img; private NGImageCallback callback; public TaskHandler(String url, View img, NGImageCallback callback) { this.url = url; this.img = img; this.callback = callback; } @Override public void handleMessage(Message msg) { final Object object = img.getTag(); if (object instanceof NGDownloadImageMode) { final NGDownloadImageMode imageMode = (NGDownloadImageMode) object; imageMode.getCallback().imageLoaded(imageMode.getParent(), img, (Bitmap) msg.obj, imageMode); if (taskMap != null) { taskMap.remove(Integer.toString(img.hashCode())); } } else if (object instanceof String) { if (callback != null) { callback.imageLoaded(null, img, (Bitmap) msg.obj, url); } else { if (object.equals(url) && msg.obj != null) { final Bitmap bitmap = (Bitmap) msg.obj; if (bitmap != null) { if (img instanceof ImageView) { ((ImageView) img).setImageBitmap(bitmap); } } } } if (taskMap != null) { taskMap.remove(Integer.toString(img.hashCode())); } } } } /** * @param url * @return Bitmap */ public Bitmap getBitmap(String url) { Bitmap bitmap = imageMemoryCache.getBitmapFromCache(url); if (bitmap == null) { bitmap = imageFileCache.getImage(url); if (bitmap == null) { bitmap = getBitmapFromUrl(url); if (bitmap != null) { imageMemoryCache.addBitmapToCache(url, bitmap); imageFileCache.saveBmpToSd(url,bitmap); } } else { imageMemoryCache.addBitmapToCache(url, bitmap); } } return bitmap; } public static Bitmap getBitmapFromUrl(String path) { try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); if (conn.getResponseCode() == 200) { InputStream inputStream = conn.getInputStream(); Bitmap bitmap = BitmapFactory.decodeStream(inputStream); return bitmap; } } catch (Exception e) { e.printStackTrace(); } return null; } public interface NGImageCallback { public void imageLoaded(Object parent, View img, Bitmap imageBitmap, NGDownloadImageMode callBackTag); public void imageLoaded(Object parent, View img, Bitmap imageBitmap, String imageUrl); } }

記憶體快取實現:
通過強&軟引用配合使用實現記憶體快取機制,強引用使用HashMap實現,軟引用使用執行緒安全的 ConcurrentHashMap實現(實現原理是鎖分離技術,使用多個鎖來控制對hash表的不同部分的修改,內部使用段(Segment)來表示這些不同的部分,每個段是一個小的hashtable,可併發執行),淘汰演算法如下:

    /**
     * 初始化
     * 淘汰最老的鍵
     */
    protected NGImageMemoryCache() {
        //使用LinkedHashMap保證有序讀取
        hashMap = new LinkedHashMap<String, Bitmap>(MAX_CACHE_CAPACITY, 0.75f, true) {
            //移除hashmap中最老的鍵值
            @Override
            protected boolean removeEldestEntry(LinkedHashMap.Entry<String, Bitmap> eldest) {
                if (size() > MAX_CACHE_CAPACITY) {
                    mSoftBitmapCache.put(eldest.getKey(), new SoftReference<Bitmap>(eldest.getValue()));
                    return true; //返回true則移除最老的鍵值
                } else {
                    return false;
                }
            }
        };
    }

外存快取實現:
很簡單這裡就只講一下思路了,把圖片檔案儲存到本地指定資料夾中,注意進行剩餘容量判斷及時清除最老的圖片就行了。