20.獲取網路圖片,將圖片儲存在檔案,快取中,然後先從快取中讀取,沒有再從檔案中讀取
實現的功能主要是標題,那麼接下來我們就分析,如何一步一步的實現這個功能
第一步:建立imgCache資料夾,在裡面建立如下幾個檔案
1.ImgLoaderCallback:用於重新整理ImageView
2.ImageManager:用於管理快取圖片,比如圖片的讀取,還有儲存
3.LazyImageLoader:非同步處理檔案管理器,比如操作獲取網路圖片的主要步驟就在裡面,
4.CallbackManager:用於回撥管理
5.建立SimplerImageLoader:真正實現網路圖片的讀取,呼叫lazyimgloader方法
6.在util中,編寫一個隊url加密的檔案
第二部:實現步驟
在LazyImageLoader中呼叫ImageManager中的方法,實現判斷這個URL有沒有,有的話就從檔案快取中讀取,沒有的話就儲存到檔案快取中,並且在LazyLoaderManager中
開啟執行緒將url放在一個Queue中,一個個的調用出來使用
第三部:下面就是原始碼
LazyImageLoader:
package imgCache; import android.content.Context; import android.graphics.Bitmap; import android.os.Bundle; import android.os.Handler; importandroid.os.Message; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import app.coolweather.com.weibo.weiboApplication; /**非同步處理圖片管理器 * Created by Administrator on 2016/9/13. */ public class LazyImageLoader { private static final int MESSAGE_ID =1; public static finalString EXTRA_IMG_URL="extra_img_url"; public static final String EXTRA_IMG="extra_img"; private Context context; private ImageManager imageManager=new ImageManager(weiboApplication.context); private BlockingQueue<String> urlQueue = new ArrayBlockingQueue<String>(50); //建立這個佇列用於存放URL,這個佇列慢的時候加入進去,為空的時候就能讀 private DownloadImage downloadImage=new DownloadImage(); private CallbackManager callbackManager=new CallbackManager(); /** *用於獲取圖片,封裝的方法在ImageManager中 */ public Bitmap get(String url,ImgLoaderCallback callback){ Bitmap bitmap = ImageManager.userDefualtHead; if(imageManager.contains(url)){ //判斷這個物件是否為空,不為空 bitmap=imageManager.getFromCache(url); //獲取圖片 return bitmap; } else{ callbackManager.put(url,callback); //在這個地方呼叫回撥管理函式,放入物件 startDownloadThread(url); //沒有else,就開啟執行緒下載 } return bitmap; } /** * 開啟執行緒 */ private void startDownloadThread(String url){ putUrlToQueue(url); Thread.State state= downloadImage.getState(); if(state== Thread.State.NEW){ //執行緒剛開啟 downloadImage.start(); }else if(state== Thread.State.TERMINATED){ //執行緒截止了 downloadImage=new DownloadImage(); downloadImage.start(); } } /** * 將url加入到queue佇列中 * 對於put方法,若向隊尾新增元素的時候發現佇列已經滿了會發生阻塞一直等待空間,以加入元素。 * add方法在新增元素的時候,若超出了度列的長度會直接丟擲異常: * offer方法在新增元素時,如果發現佇列已滿無法新增的話,會直接返回false。 */ private void putUrlToQueue(String url){ if(!urlQueue.contains(url)){ try { urlQueue.put(url); } catch (InterruptedException e) { e.printStackTrace(); } } } Handler handler=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case MESSAGE_ID: //獲取檔案或者下載的圖片,實現UI的更新 { Bundle bundle=msg.getData(); // 獲取資料 String url =bundle.getString(EXTRA_IMG_URL); Bitmap bitmap = bundle.getParcelable(EXTRA_IMG); callbackManager.callback(url,bitmap); break; } } } }; //建立一個內部類用於開啟執行緒,來下載圖片 private class DownloadImage extends Thread{ private boolean isRun=true; @Override public void run() { super.run(); try{ while(isRun){ String url=urlQueue.poll(); //從佇列中獲取一個並且刪除這個 if(url==null){break;} Bitmap bitmap=imageManager.safeGet(url); //返回從檔案中查詢到的,或者下載的圖片 Message message=handler.obtainMessage(MESSAGE_ID); //在自定義handler中,儘量使用這種方法,而不是new Message() Bundle bundle=message.getData(); //第一句的意思是獲取傳遞過來的Message中的資料集合. bundle.putSerializable(EXTRA_IMG_URL, url); //Bundle的內部實際上是使用了HashMap型別的變數來存放putXxx()方法放入的值 bundle.putParcelable(EXTRA_IMG, bitmap); handler.sendMessage(message); } }catch (Exception E){ } finally { isRun=false; //當執行緒執行完畢的時候關閉,要不然會一直執行 } } } }
ImageManager:
package imgCache; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import org.apache.commons.httpclient.HttpException; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.lang.ref.SoftReference; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.Map; import Util.MD5Util; /**用於管理快取圖片 * Created by Administrator on 2016/9/13. */ public class ImageManager { Map<String,SoftReference<Bitmap>> imgCache; //用map是為了快取儲存物件,用,SoftReference<Bitmap>是為了更 private Context context; public static Bitmap userDefualtHead; public ImageManager(Context context){ imgCache = new HashMap<String, SoftReference<Bitmap>>(); //在建構函式進行例項化 this.context=context; } /**判斷快取中是否含有這個圖片 *Map containsKey(String Key) 判斷key有沒有對應的value值; 有,則返回true 沒有,則返回false */ public boolean contains(String url){ return imgCache.containsKey(url); } /** *先判斷從Map快取中讀取資料,如果沒有就從file中讀取,file位於該包下面 */ public Bitmap getFromCache(String url) { Bitmap bitmap = null; bitmap = this.getFromMapCache(url); if(null == bitmap) { bitmap =getFromFile(url); } return bitmap; } /** * 從Map快取中獲取BitMap * Java語言的關鍵字,當它synchronized 用來修飾一個方法或者一個程式碼塊的時候,能夠保證在同一時刻最多隻有一個執行緒執行該段程式碼。 */ public Bitmap getFromMapCache(String url) { Bitmap bitmap = null; SoftReference<Bitmap> ref = null; //SoftReference<BitMap>與bitmap不一樣 synchronized (this) { ref = imgCache.get(url); } if(null != ref) { bitmap = ref.get(); } return bitmap; } /** * 從檔案中獲取Bitmap * @param url * @return */ public Bitmap getFromFile(String url) { String fileName = this.getMd5(url); FileInputStream is=null; try { is=context.openFileInput(fileName); //fileName的name不能包含分隔符 return BitmapFactory.decodeStream(is); //將獲取的資源解析成bitmap } catch (FileNotFoundException e) { return null; } finally { if(null != is) { try{is.close();}catch(Exception ex){}; } } } /** * 檢視檔案中有沒有圖片,有的話放入快取當中,沒有的話就下載 */ public Bitmap safeGet(String url) throws HttpException { Bitmap bitmap = this.getFromFile(url); if(null != bitmap) { synchronized (this) { imgCache.put(url, new SoftReference<Bitmap>(bitmap)); } return bitmap; } return downloadImage(url); } /** * 下載圖片並保持檔案到系統快取 */ public Bitmap downloadImage(String urlStr)throws HttpException { try { URL url=new URL(urlStr); try { HttpURLConnection connection =(HttpURLConnection) url.openConnection(); //獲取網路連線 String fileName=writerToFile(getMd5(urlStr),connection.getInputStream()); //儲存成功返還檔名 return BitmapFactory.decodeFile(fileName); //將系統中的檔案轉化為一個bitmap圖片 } catch (IOException e) { e.printStackTrace(); } } catch (MalformedURLException e) { e.printStackTrace(); } return null; } /** * 獲取的網路圖片,寫入到檔案還有快取中 */ public String writerToFile(String fileName, InputStream is) { BufferedInputStream bis = null; //讀取檔案 BufferedOutputStream bos = null; //儲存資料到檔案 try { bis = new BufferedInputStream(is); bos = new BufferedOutputStream(context.openFileOutput(fileName, Context.MODE_PRIVATE)); byte[] buffer = new byte[1024]; //放入快取當中 int length; while((length = bis.read(buffer)) != -1) { bos.write(buffer, 0, length); } } catch (Exception e) { } finally { try { if(null != bis) { bis.close(); } if(null != bos) { bos.flush(); bos.close(); } } catch (IOException e) { e.printStackTrace(); } } return context.getFilesDir() + "/" + fileName; } /** * 呼叫Md5方法,用於對URL加密 */ private String getMd5(String src) { return MD5Util.getMD5String(src); } }
lmgLoaderCallback:
/**只管重新整理ImageView * Created by Administrator on 2016/9/13. */ public interface ImgLoaderCallback { void refresh(String url, Bitmap bitmap); //用於重新整理ImageView,Bitmap用於儲存網路上獲取的圖片 }
simplemageLoader:
package imgCache; import android.graphics.Bitmap; import android.widget.ImageView; import app.coolweather.com.weibo.weiboApplication; /** * Created by Administrator on 2016/9/20. */ public class SimpleImageLoader { public static void showImg(ImageView view,String url) { view.setTag(url); view.setImageBitmap(weiboApplication.lazyImageLoader.get(url, getCallback(url,view))); } private static ImgLoaderCallback getCallback(final String url,final ImageView view) { return new ImgLoaderCallback() { @Override public void refresh(String url, Bitmap bitmap) { if(url.equals(view.getTag().toString())) { view.setImageBitmap(bitmap); } } }; } }
CallbackManager:
package imgCache; import android.graphics.Bitmap; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; /**用於回撥管理 * Created by Administrator on 2016/9/13. */ public class CallbackManager { private ConcurrentHashMap<String, List<ImgLoaderCallback>> callbackMap; //建立頁面重新整理物件 public CallbackManager() { callbackMap = new ConcurrentHashMap<String, List<ImgLoaderCallback>>(); //進行例項化 } /** * 在陣列中放入物件 */ public void put(String url,ImgLoaderCallback callback) { if(!callbackMap.contains(url)) //沒有這個url,就建立這個url的陣列,用於儲存imgloaderCallback物件 callbackMap.put(url, new ArrayList<ImgLoaderCallback>()); callbackMap.get(url).add(callback); } public void callback(String url,Bitmap bitmap) //獲取物件實現重新整理頁面 { List<ImgLoaderCallback> callbacks =callbackMap.get(url); if(null == callbacks) return; for (ImgLoaderCallback callback : callbacks) { if(null != callback) callback.refresh(url, bitmap); } callbacks.clear(); callbackMap.remove(url); } }
util中檔案的原始碼:MD5Util
package Util; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * @author Ivan * @version 1.0 * @briefMD5工具類,提供字串MD5加密(校驗)、檔案MD5值獲取(校驗)功能。 */ public class MD5Util { /** * 16進位制字符集 */ private static final char HEX_DIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; /** * 指定演算法為MD5的MessageDigest */ private static MessageDigest messageDigest = null; /** * 初始化messageDigest的加密演算法為MD5 */ static { try { messageDigest = MessageDigest.getInstance("MD5"); } catch(NoSuchAlgorithmException e) { e.printStackTrace(); } } /** * MD5加密字串 * @param str 目標字串 * @return MD5加密後的字串 */ public static String getMD5String(String str) { return getMD5String(str.getBytes()); } /** * MD5加密以byte陣列表示的字串 * @param bytes 目標byte陣列 * @return MD5加密後的字串 */ public static String getMD5String(byte[] bytes) { messageDigest.update(bytes); return bytesToHex(messageDigest.digest()); } /** * 將位元組陣列轉換成16進位制字串 * @param bytes 目標位元組陣列 * @return 轉換結果 */ public static String bytesToHex(byte bytes[]) { return bytesToHex(bytes, 0, bytes.length); } /** * 將位元組陣列中指定區間的子陣列轉換成16進位制字串 * @param bytes 目標位元組陣列 * @param start 起始位置(包括該位置) * @param end 結束位置(不包括該位置) * @return 轉換結果 */ public static String bytesToHex(byte bytes[], int start, int end) { StringBuilder sb = new StringBuilder(); for(int i = start; i < start + end; i++) { sb.append(byteToHex(bytes[i])); } return sb.toString(); } /** * 將單個位元組碼轉換成16進位制字串 * @param bt 目標位元組 * @return 轉換結果 */ public static String byteToHex(byte bt) { return HEX_DIGITS[(bt & 0xf0) >> 4] + "" + HEX_DIGITS[bt & 0xf]; } }
最後一步:呼叫
SimpleImageLoader.showImg(holder.user_head,"http://image6.huangye88.com/2013/07/26/370d6cd0c79c4269.jpg");
1.傳入你需要的url就行
2.SimpleImageLoader.showImg(holder.img_wb_item_head, s.getUser().getProfileImageURL().toString()); 還可以呼叫介面獲取裡裡面的圖片