(MyStudy:一)三級快取:首先是記憶體-檔案(外存)-網路三級快取機制。
阿新 • • 發佈:2019-01-30
三級快取:首先是記憶體-檔案(外存)-網路三級快取機制。
首先:
框架需要一個接入方法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;
}
}
};
}
外存快取實現:
很簡單這裡就只講一下思路了,把圖片檔案儲存到本地指定資料夾中,注意進行剩餘容量判斷及時清除最老的圖片就行了。