android中圖片的三級cache策略(記憶體、檔案、網路) 一

來源:互聯網
上載者:User

1. 簡介

現在android應用中不可避免的要使用圖片,有些圖片是可以變化的,需要每次啟動時從網路拉取,這種情境在有廣告位的應用以及純圖片應用(比如百度美拍)中比較多。

現在有一個問題:假如每次啟動的時候都從網路拉取圖片的話,勢必會消耗很多流量。在當前的狀況下,對於非wifi使用者來說,流量還是很貴的,一個很耗流量的應用,其使用者數量級肯定要受到影響。當然,我想,向百度美拍這樣的應用,必然也有其內部的圖片緩衝策略。總之,圖片緩衝是很重要而且是必須的。

 

2.圖片緩衝的原理

實現圖片緩衝也不難,需要有相應的cache策略。這裡我採用 記憶體-檔案-網路 三層cache機制,其中記憶體緩衝包括強引用緩衝和軟引用緩衝(SoftReference),其實網路不算cache,這裡姑且也把它划到緩衝的階層中。當根據url向網路拉取圖片的時候,先從記憶體中找,如果記憶體中沒有,再從快取檔案中尋找,如果快取檔案中也沒有,再從網路上通過http請求拉取圖片。在索引值對(key-value)中,這個圖片緩衝的key是圖片url的hash值,value就是bitmap。所以,按照這個邏輯,只要一個url被下載過,其圖片就被緩衝起來了。

關於Java中對象的軟引用(SoftReference),如果一個對象具有軟引用,記憶體空間足夠,垃 圾回收器就不會回收它;如果記憶體空間不足了,就會回收這些對象的記憶體。只要記憶體回收行程沒有回收它,該對象就可以被程式使用。軟引用可用來實現記憶體敏感的高 速緩衝。使用軟引用能防止記憶體泄露,增強程式的健壯性。  

從代碼上來說,採用一個ImageManager來負責圖片的管理和緩衝,函數介面為public void loadBitmap(String url, Handler handler) ;其中url為要下載的圖片地址,handler為圖片下載成功後的回調,在handler中處理message,而message中包含了圖片的資訊以及bitmap對象。ImageManager中使用的ImageMemoryCache(記憶體緩衝)、ImageFileCache(檔案快取)以及LruCache(最近最久未使用緩衝)會在後續文章中介紹。

3.代碼ImageManager.java

 

/* * 圖片管理 * 非同步擷取圖片,直接調用loadImage()函數,該函數自己判斷是從緩衝還是網路載入 * 同步擷取圖片,直接調用getBitmap()函數,該函數自己判斷是從緩衝還是網路載入 * 僅從本地擷取圖片,調用getBitmapFromNative() * 僅從網路載入圖片,調用getBitmapFromHttp() *  */public class ImageManager implements IManager{private final static String TAG = "ImageManager";private ImageMemoryCache imageMemoryCache; //記憶體緩衝private ImageFileCache   imageFileCache; //檔案快取//正在下載的image列表public static HashMap<String, Handler> ongoingTaskMap = new HashMap<String, Handler>();//等待下載的image列表public static HashMap<String, Handler> waitingTaskMap = new HashMap<String, Handler>();//同時下載圖片的線程個數final static int MAX_DOWNLOAD_IMAGE_THREAD = 4;private final Handler downloadStatusHandler = new Handler(){public void handleMessage(Message msg){startDownloadNext();}};public ImageManager(){imageMemoryCache = new ImageMemoryCache();imageFileCache = new ImageFileCache();    }    /**     * 擷取圖片,多線程的入口     */    public void loadBitmap(String url, Handler handler)     {        //先從記憶體緩衝中擷取,取到直接載入        Bitmap bitmap = getBitmapFromNative(url);                if (bitmap != null)        {            Logger.d(TAG, "loadBitmap:loaded from native");        Message msg = Message.obtain();            Bundle bundle = new Bundle();            bundle.putString("url", url);            msg.obj = bitmap;            msg.setData(bundle);            handler.sendMessage(msg);        }         else        {        Logger.d(TAG, "loadBitmap:will load by network");        downloadBmpOnNewThread(url, handler);        }    }        /**     * 新起線程下載圖片     */    private void downloadBmpOnNewThread(final String url, final Handler handler)    {Logger.d(TAG, "ongoingTaskMap'size=" + ongoingTaskMap.size());    if (ongoingTaskMap.size() >= MAX_DOWNLOAD_IMAGE_THREAD) {synchronized (waitingTaskMap) {waitingTaskMap.put(url, handler);}} else {synchronized (ongoingTaskMap) {ongoingTaskMap.put(url, handler);}new Thread() {public void run() {Bitmap bmp = getBitmapFromHttp(url);// 不論下載是否成功,都從下載隊列中移除,再由商務邏輯判斷是否重新下載// 下載圖片使用了httpClientRequest,本身已經帶了重連機制synchronized (ongoingTaskMap) {ongoingTaskMap.remove(url);}if(downloadStatusHandler != null){downloadStatusHandler.sendEmptyMessage(0);}Message msg = Message.obtain();msg.obj = bmp;Bundle bundle = new Bundle();bundle.putString("url", url);msg.setData(bundle);if(handler != null){handler.sendMessage(msg);}}}.start();}}    /**     * 依次從記憶體,快取檔案,網路上載入單個bitmap,不考慮線程的問題     */public Bitmap getBitmap(String url){    // 從記憶體緩衝中擷取圖片    Bitmap bitmap = imageMemoryCache.getBitmapFromMemory(url);    if (bitmap == null)     {        // 檔案快取中擷取    bitmap = imageFileCache.getImageFromFile(url);        if (bitmap != null)         {                    // 添加到記憶體緩衝        imageMemoryCache.addBitmapToMemory(url, bitmap);        }         else         {            // 從網路擷取        bitmap = getBitmapFromHttp(url);        }    }    return bitmap;}/** * 從記憶體或者快取檔案中擷取bitmap */public Bitmap getBitmapFromNative(String url){Bitmap bitmap = null;bitmap = imageMemoryCache.getBitmapFromMemory(url);if(bitmap == null){bitmap = imageFileCache.getImageFromFile(url);if(bitmap != null){// 添加到記憶體緩衝imageMemoryCache.addBitmapToMemory(url, bitmap);}}return bitmap;}/** * 通過網路下載圖片,與線程無關 */public Bitmap getBitmapFromHttp(String url){Bitmap bmp = null;try{byte[] tmpPicByte = getImageBytes(url);if (tmpPicByte != null) {bmp = BitmapFactory.decodeByteArray(tmpPicByte, 0,tmpPicByte.length);}tmpPicByte = null;}catch(Exception e){e.printStackTrace();}if(bmp != null){// 添加到檔案快取imageFileCache.saveBitmapToFile(bmp, url);// 添加到記憶體緩衝imageMemoryCache.addBitmapToMemory(url, bmp);}return bmp;}/** * 下載連結的圖片資源 *  * @param url *             * @return 圖片 */public byte[] getImageBytes(String url) {byte[] pic = null;if (url != null && !"".equals(url)) {Requester request = RequesterFactory.getRequester(Requester.REQUEST_REMOTE, RequesterFactory.IMPL_HC);// 執行請求MyResponse myResponse = null;MyRequest mMyRequest;mMyRequest = new MyRequest();mMyRequest.setUrl(url);mMyRequest.addHeader(HttpHeader.REQ.ACCEPT_ENCODING, "identity");InputStream is = null;ByteArrayOutputStream baos = null;try {myResponse = request.execute(mMyRequest);is = myResponse.getInputStream().getImpl();baos = new ByteArrayOutputStream();byte[] b = new byte[512];int len = 0;while ((len = is.read(b)) != -1) {baos.write(b, 0, len);baos.flush();}pic = baos.toByteArray();Logger.d(TAG, "icon bytes.length=" + pic.length);} catch (Exception e3) {e3.printStackTrace();try {Logger.e(TAG,"download shortcut icon faild and responsecode="+ myResponse.getStatusCode());} catch (Exception e4) {e4.printStackTrace();}} finally {try {if (is != null) {is.close();is = null;}} catch (Exception e2) {e2.printStackTrace();}try {if (baos != null) {baos.close();baos = null;}} catch (Exception e2) {e2.printStackTrace();}try {request.close();} catch (Exception e1) {e1.printStackTrace();}}}return pic;}/** * 取出等待隊列第一個任務,開始下載 */private void startDownloadNext(){synchronized(waitingTaskMap){Logger.d(TAG, "begin start next");Iterator iter = waitingTaskMap.entrySet().iterator(); while (iter.hasNext()) {Map.Entry entry = (Map.Entry) iter.next();Logger.d(TAG, "WaitingTaskMap isn't null,url=" + (String)entry.getKey());if(entry != null){waitingTaskMap.remove(entry.getKey());downloadBmpOnNewThread((String)entry.getKey(), (Handler)entry.getValue());}break;}}}public String startDownloadNext_ForUnitTest(){String urlString = null;synchronized(waitingTaskMap){Logger.d(TAG, "begin start next");Iterator iter = waitingTaskMap.entrySet().iterator(); while (iter.hasNext()) {Map.Entry entry = (Map.Entry) iter.next();urlString = (String)entry.getKey();waitingTaskMap.remove(entry.getKey());break;}}return urlString;}/** * 圖片變為圓角 * @param bitmap:傳入的bitmap * @param pixels:圓角的度數,值越大,圓角越大 * @return bitmap:加入圓角的bitmap */public static Bitmap toRoundCorner(Bitmap bitmap, int pixels) {         if(bitmap == null)        return null;        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);         Canvas canvas = new Canvas(output);          final int color = 0xff424242;         final Paint paint = new Paint();         final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());         final RectF rectF = new RectF(rect);         final float roundPx = pixels;          paint.setAntiAlias(true);         canvas.drawARGB(0, 0, 0, 0);         paint.setColor(color);         canvas.drawRoundRect(rectF, roundPx, roundPx, paint);          paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));         canvas.drawBitmap(bitmap, rect, rect, paint);          return output;     }public byte managerId() {return IMAGE_ID;}}

 

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.