三級緩存分別是:html
軟引用SoftReference,cache在內存中web
文件緩存在本地SDcard文件夾中,遇到文件名相同的圖片則從本地取,且加入軟引用中緩存
從網絡下載,並保存在本地,且加入軟引用中網絡
其中緩存的文件,其文件名通過MD5轉換,去掉了文件路徑中的斜槓,目前該方法全存儲成png格式的,也可進一步優化。注意須要靜態初始化軟引用,可保證全局有效。異步
實現的方法是經過集成一個AsyncTask,並定製裏面的內容。好像也沒什麼特別好說的...ide
在作listview列表的時候,可把這一個task加入viewholder裏,這樣就能保證每一個控件的惟一性了,比起封裝一個AsyncImageView,要更簡潔一些,而且能知足使用的要求工具
代碼以下:優化
/** * 異步根據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/1118828http://blog.csdn.net/geniusxiaoyu/article/details/7470163http://blog.csdn.net/zshshuai/article/details/7798086 http://www.2cto.com/kf/201403/283382.htmlthis
以上幾篇代碼沒有提到LRU的實現,使用LRU能夠真正的吸收內存空間作緩存,可是目前我實現的代碼不怎麼有效,在此處mark一下,調成功以後再更新這個封裝類url