Android 圖片三級緩存機制工具類封裝

Android 圖片三級緩存機制工具類封裝

三級緩存分別是:html

  1. 軟引用SoftReference,cache在內存中
  2. 文件緩存在本地SDcard文件夾中,遇到文件名相同的圖片則從本地取,且加入軟引用中
  3. 從網絡下載,並保存在本地,且加入軟引用中

其中緩存的文件,其文件名通過MD5轉換,去掉了文件路徑中的斜槓,目前該方法全存儲成png格式的,也可進一步優化。注意須要靜態初始化軟引用,可保證全局有效。緩存

實現的方法是經過集成一個AsyncTask,並定製裏面的內容。好像也沒什麼特別好說的...網絡

在作listview列表的時候,可把這一個task加入viewholder裏,這樣就能保證每一個控件的惟一性了,比起封裝一個AsyncImageView,要更簡潔一些,而且能知足使用的要求異步

代碼以下:ide

/**
 * 異步根據URL獲取圖片
 * 修改加入本地緩存和軟引用
 * @author Jackland_zgl
 *
 */
@SuppressLint("NewApi")
public class LoadingImgTask extends AsyncTask<Void, Void, Bitmap> {

    public static final String URL_KEY = "url";
    public static final String BITMAP_KEY = "bitmap";

    public static final String ImageCacheFilePath = "/sdcard/xiaomai/ImageCache/";
    private String url;
    private static HashMap<String, SoftReference<Bitmap>> cache; 
    RefreshDelegate  refreshDelegate;

    /** 靜態初始化軟引用 */
    static {  
        cache = new HashMap<String, SoftReference<Bitmap>>();  
    }


    public LoadingImgTask(String url,RefreshDelegate rd) {
        this.url = url;
        this.refreshDelegate = rd;
    }

    @Override
    protected Bitmap doInBackground(Void... params) {

        Bitmap bm;
        //1從軟引用中取
        bm = getBitmapFromCache(url);
        if (bm!=null) {
//          Log.d("image","緩存");
            return bm;
        }

        //2從本地中取
        bm = getBitmapFromLocal(ImageCacheFilePath , modifyUriToFileName(url));
        if (bm!=null) {
            //放入緩存
            cache.put(url, new SoftReference<Bitmap>(bm));
//          Log.d("image","本地");
            return bm;
        }

        //3從網絡取 ,若能取出則緩存
        bm = loadImageFromNet(url);
        if (bm!=null){
            try {
                saveImageToSD(ImageCacheFilePath+modifyUriToFileName(url),bm);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            cache.put(url, new SoftReference<Bitmap>(bm));
//          Log.d("image","網絡");
        }
        return bm;
    }

    @Override
    protected void onPostExecute(Bitmap result) {
        HashMap<String,Object> map = new HashMap<String,Object>();
        map.put(RefreshDelegate.KEY_URL, url);
        map.put(RefreshDelegate.KEY_BITMAP, result);
        if (refreshDelegate!=null)
            refreshDelegate.refresh(map);
    }

    /**
     * 從緩存中獲取圖片
     * @param url
     */
    public Bitmap getBitmapFromCache(String url) {  
        Bitmap bitmap = null;
        if (cache.containsKey(url)) {  
            bitmap = cache.get(url).get();  
        }  
        return bitmap;  
    }  

    /**
     * 從本地獲取
     * @param path
     * @param url
     * @return
     */
    public Bitmap getBitmapFromLocal(String path,String url){
        return BitmapFactory.decodeFile(path+url);

    } 

    /**
     * 從網絡讀取
     * @param url
     * @return
     */
    public static Bitmap loadImageFromNet(String url) {
        URL m;
        InputStream i = null;
        if (url == null) {
            return null;
        }
        try {
            m = new URL(url);

            i = (InputStream) m.getContent();
        } catch (MalformedURLException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e2) {
            e2.printStackTrace();
        }
        if (i == null) {
            return null;
        }
        return BitmapFactory.decodeStream(i);
    }

    /**
     * 寫圖片文件到SD卡
     * 
     * @throws IOException
     */
    public static void saveImageToSD(String filePath,
            Bitmap bitmap) throws IOException {
        Log.d("image","存在本地:"+filePath);
        if (bitmap != null) {
            File file = new File(filePath.substring(0,
                    filePath.lastIndexOf(File.separator)));
            if (!file.exists()) {
                file.mkdirs();
            }
            FileOutputStream fos = new FileOutputStream(filePath);
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            bitmap.compress(CompressFormat.PNG, 100, stream);

            fos.write(stream.toByteArray());
            fos.close();
        }
    }

    /**
     * 修改URL裏的斜槓
     * @param Url
     * @return
     */
    public static String modifyUriToFileName(String Url){
//      String mUrl = Url.replaceAll("/", "_").replaceAll("\\.", "-").replaceAll(":", "_")+".jpg";
        String mUrl = MD5Util.md5(Url)+".png";
        return mUrl;
    }


    /**
     * 刷新代理
     * @author Jackland_zgl
     *
     */
    public interface RefreshDelegate{
        public static String KEY_URL="url";
        public static String KEY_BITMAP="bitmap";

        public int refresh(HashMap<String,Object> result);

    }
}

關於異步加載圖片,下面的幾篇博客可供參考:
http://www.iteye.com/topic/1118828
http://blog.csdn.net/geniusxiaoyu/article/details/7470163
http://blog.csdn.net/zshshuai/article/details/7798086
http://www.2cto.com/kf/201403/283382.html工具

以上幾篇代碼沒有提到LRU的實現,使用LRU能夠真正的吸收內存空間作緩存,可是目前我實現的代碼不怎麼有效,在此處mark一下,調成功以後再更新這個封裝類優化


文章爲原創,轉載請註明出處。this

相關文章
相關標籤/搜索