工作中圖片的三級緩存機制介紹

現在android應用中不可避免的要使用圖片,有些圖片是可以變化的,需要每次啓動時從網絡拉取,這種場景在目前市場的應用以及純圖片應用(比如百度美拍)中比較多。
實現圖片緩存也不難,需要有相應的cache策略。這裏我採用 內存(memory)-本地(local)-網絡(Internet) 三層cache機制,其實網絡不算cache。
當根據url向網絡拉取圖片的時候,先從本應用內存中找,如果內存中沒有,再從本地緩存文件中查找,如果緩存文件中也沒有,再從網絡上通過http請求拉取圖 片。在鍵值對(key-value)中,這個圖片緩存的key是圖片url的hash值,value就是bitmap。所以,按照這個邏輯,只要一個 url被下載過,其圖片就被緩存起來了。

三級緩存的比較:
-內存緩存,優先加載,速度最快
-本地緩存,次優先加載,速度快
-網絡緩存,不優先加載,速度慢,浪費流量。

現在我們來看看怎麼去實現這個緩存。

首先是網絡緩存的類:

/**
 * 
 * 從網絡下載圖片
 * @lly
 *
 */
public class NetCacheUtils {
    private LocalCacheUtils mlocalcacheutils;
    private MemoryCacheUtils mmemorycacheutils;

    public NetCacheUtils(LocalCacheUtils localcacheutils, MemoryCacheUtils memorycacheutils) {
        mlocalcacheutils=localcacheutils;
        mmemorycacheutils=memorycacheutils;
    }

    public void getBitmapFromNet(ImageView iv_photo, String url) {
        // TODO Auto-generated method stub
        BitmapTask bitmaptask=new BitmapTask();
        bitmaptask.execute(iv_photo,url);//開啓AsyncTask,參數在doInBackground獲取
    }
    /*AsyncTask  異步任務即做一些簡單的異步處理  ;是handle與線程池的封裝
     * 第一個泛型:參數類型泛型
     * 第二個泛型:更新進度泛型
     * 第三個泛型:onProgressUpdate的返回結果的泛型
     * 
     */
    
    class BitmapTask extends AsyncTask<Object, Void, Bitmap>{

        private ImageView pic;
        private String murl;
        /**
         * 後臺耗時方法在此執行,子線程
         */
        @Override
        protected Bitmap doInBackground(Object... params) {
            pic = (ImageView) params[0];
            murl = (String) params[1];
            
            pic.setTag(murl);//將圖片與url綁定
            return downloadBitmap(murl);
        }
        /**
         * 更新進度,主線程
         */
        @Override
        protected void onProgressUpdate(Void... values) {
            // TODO Auto-generated method stub
            super.onProgressUpdate(values);
        }
        /**
         * 後臺耗時方法結束之後,在此執行,主線程
         */
        @Override
        protected void onPostExecute(Bitmap result) {
            if(result!=null){
                
                String tag = (String) pic.getTag();
                if(tag.equals(murl)){
                    pic.setImageBitmap(result);
                }
                
            }
            mlocalcacheutils.setBitmapTolocal(murl, result);
            mmemorycacheutils.setBitmapTomemory(murl, result);
            System.out.println("從網絡上加載圖片啦");
            
        }
    }

    /**
     * 
     * 下載圖片
     * @return 
     */
    private Bitmap downloadBitmap(String url){
        HttpURLConnection conn=null;
        try {
            conn=(HttpURLConnection) new URL(url)
            .openConnection();
            
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(5000);
            conn.setRequestMethod("GET");
            conn.connect();
            
            int responseCode = conn.getResponseCode();//響應碼
            
            if(responseCode==200){//表示成功連接
                InputStream inputStream = conn.getInputStream();
                Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                return bitmap;
            }
            
        } catch (IOException e) {
            
            e.printStackTrace();
        }
        finally{
            conn.disconnect();
        }
        return null;
        
    }
}

本地緩存的實現:

public class LocalCacheUtils {
    private static final String CACHE_PATH=Environment.getExternalStorageDirectory()
            .getAbsolutePath()+"/zhbj_cache_52";
/**
 * 
 * 從本地讀圖片
 * @param url
 */
    public Bitmap getBitmapFromlocal(String url){
        try {
            String filename = MD5Encoder.encode(url);
            
            File file=new File(CACHE_PATH, filename);//通過父文件夾與自己的文件名稱來創建一個文件
            
            if(file.exists()){
                Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(file));
                return bitmap;
            }
            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
        
    }
    
/**
 * 
 * 將圖片寫到本地
 * @param url
 * @param bitmap
 */
    public void setBitmapTolocal(String url,Bitmap bitmap){
        try {
            String filename = MD5Encoder.encode(url);
            File file=new File(filename);
            File parentFile = file.getParentFile();
            if(!parentFile.exists()){//如果文件夾不存在,則創建
                file.mkdirs();
            }
            //將圖片保存到本地
            bitmap.compress(CompressFormat.JPEG, 100, 
                    new FileOutputStream(file));
                
    
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
    
}

接下來是內存緩存的實現:

/**
 * 
 * 內存緩存
 * @lly
 *
 */
public class MemoryCacheUtils {
 
    private HashMap<String, Bitmap> hashlist=new HashMap<String, Bitmap>();
    /**
     * 
     * 從內存中讀
     * @param url
     * @return
     */
    public  Bitmap getBitmapFrommemory(String url){
        Bitmap bitmap = hashlist.get(url);
        return bitmap;
    }
    

    /**
     * 
     * 寫入內存
     * @param url
     * @param bitmap
     */
    public  void setBitmapTomemory(String url,Bitmap bitmap){
        hashlist.put(url, bitmap);
    }
}

最後是我們自己實現的圖片加載工具:

/**
 * 
 * 圖片加載工具
 * @lly
 *
 */
public class BitMaputils {
    NetCacheUtils netcache;
    LocalCacheUtils localcacheutils;
    MemoryCacheUtils memorycacheutils;
    public BitMaputils(){
        memorycacheutils=new MemoryCacheUtils();
        localcacheutils=new LocalCacheUtils();
        netcache=new NetCacheUtils(localcacheutils,memorycacheutils);
        
    }
    Bitmap bitmap =null;
    public void display(ImageView iv_photo, String url) {
        iv_photo.setImageResource(R.drawable.news_pic_default);//默認圖片,防止圖片的複用
        //內存緩存
        bitmap= memorycacheutils.getBitmapFrommemory(url);
        if(bitmap!=null){
            iv_photo.setImageBitmap(bitmap);
            System.out.println("從內存中讀取圖片");
            return;
        }
        //本地緩存
        bitmap = localcacheutils.getBitmapFromlocal(url);
        if(bitmap!=null){
            iv_photo.setImageBitmap(bitmap);
            memorycacheutils.setBitmapTomemory(url, bitmap);
            System.out.println("從本地讀取圖片");
            return;//從本地讀取就不需要從網絡讀取了
        }
        
        //網絡緩存(第一次)
        netcache.getBitmapFromNet(iv_photo,url);
    }

    
}

 

圖片框架:Android-Universal-Image-Loader 也是採用了三級緩存的思路。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章