1. 程式人生 > >安卓andbase框架原始碼解讀(二)

安卓andbase框架原始碼解讀(二)

上一次分析了andbase框架的AbActivity 安卓andbase框架原始碼解讀(一),不知道有沒有讓大家對這個框架產生點興趣,這次我要分析的是一個平常比較常用也比較簡單但是還挺煩人的知識點:下載圖片,當然現在有很多框架比如ImageLoader,Volley裡的專門用來從網上載入資料的NetworkImageView,效能還都是不錯的,以後博主也一定會把這些原始碼都分析一下的,畢竟reading the fucking source code還是可以讓我們加深對知識的理解,提高自己的水平的。那麼,我就開始今天的分析了

andbase框架下載圖片使用的AsyncTask,LruCache,在本次sdcard上的快取原作者也是自己實現的,其實也可以用谷歌的DiskLruCache實現可能更方便一點,當然這麼寫可能是因為原作者太牛了。。。

首先圖片下載當然是要單獨開執行緒的了,這裡用到的是AbImageDownloadTask,繼承自AsyncTask,

public class AbImageDownloadTask extends AsyncTask<AbImageDownloadItem, Integer, AbImageDownloadItem>
我們都知道這個類處理後臺任務的方法都是在doInBackground中的,那麼就讓我們看一下這個方法,
/**  
     * 這裡的第一個引數對應AsyncTask中的第一個引數   
     * 這裡的String返回值對應AsyncTask的第三個引數  
     * 該方法並不執行在UI執行緒當中,主要用於非同步操作,所有在該方法中不能對UI當中的空間進行設定和修改  
     * 但是可以呼叫publishProgress方法觸發onProgressUpdate對UI進行操作  
     */  
	@Override
	protected AbImageDownloadItem doInBackground(AbImageDownloadItem... items) {
		AbImageDownloadItem item = items[0];
		//檢查圖片路徑
    	String url = item.imageUrl;
    	if(AbStrUtil.isEmpty(url)){
    		if(D)Log.d(TAG, "圖片URL為空,請先判斷");
    	}else{
    		url = url.trim();
    	}
    	
    	String cacheKey = AbImageCache.getCacheKey(url, item.width, item.height, item.type);
		item.bitmap =  AbImageCache.getBitmapFromCache(cacheKey);
    	if(item.bitmap == null){
    		//開始下載
            item.bitmap = AbFileUtil.getBitmapFromSDCache(item.imageUrl,item.type,item.width,item.height);
            //快取圖片路徑
            AbImageCache.addBitmapToCache(cacheKey,item.bitmap);                                           
            //需要執行回撥來顯示圖片
            if (item.listener != null) {
                Message msg = handler.obtainMessage(); 
                msg.obj = item; 
                handler.sendMessage(msg); 
            }
		}else{
			if(D) Log.d(TAG, "從記憶體快取中得到圖片:"+cacheKey+","+item.bitmap);
			if (item.listener != null) {
                Message msg = handler.obtainMessage(); 
                msg.obj = item; 
                handler.sendMessage(msg); 
            }
	    }
		return item;
	}
首先要是用這個類,我們要在它的execute()方法中傳進去一個型別為AbImageDownloadItem的引數,這個類就相當於是我們平常用的實體類,
public class AbImageDownloadItem {
	
	/** 需要下載的圖片的網際網路地址. */
	public String imageUrl;
	
	/** 顯示的圖片的寬. */
	public int width;
	
	/** 顯示的圖片的高. */
	public int height;
	
	/** 圖片的處理型別(剪下或者縮放到指定大小,參考AbConstant類). */
	public int type;
	
	/** 下載完成的到的Bitmap物件. */
	public Bitmap bitmap;
	
	/** 下載完成的回撥介面. */
	public AbImageDownloadListener listener;
}
這裡面還有相對應的get和set方法,我就不貼了,屬性的作用在註釋裡寫的也很清楚了(不是本人寫的,是原作者的功勞,贊一個),我們可以看到在後臺處理的方法裡,首先判斷傳進去的引數是不是空,是的話直接返回錯誤資訊,否則從快取中找是不是已經載入過這張圖片了,是的話通過Handler釋出資訊,進行非同步處理(這裡估計是原作者寫重複了,因為我們一會會看到handler的處理和afterExecute方法裡執行的動作是一樣的,這樣寫的話不是會執行兩次更新函式嗎),如果現在記憶體中沒有快取的話,那就要看看sdcard上有沒有了,用的是getBitmapFromSDCache這個方法
 /**
	  * 描述:通過檔案的網路地址從SD卡中讀取圖片,如果SD中沒有則自動下載並儲存.
	  * @param url 檔案的網路地址
	  * @param type 圖片的處理型別(剪下或者縮放到指定大小,參考AbConstant類)
	  * 如果設定為原圖,則後邊引數無效,得到原圖
	  * @param width 新圖片的寬
	  * @param height 新圖片的高
	  * @return Bitmap 新圖片
	  */
	 public static Bitmap getBitmapFromSDCache(String url,int type,int width, int height){
		 Bitmap bitmap = null;
		 try {
			 if(AbStrUtil.isEmpty(url)){
		    	return null;
		     }
			 
			 //SD卡不存在 或者剩餘空間不足了就不快取到SD卡了
			 if(!isCanUseSD() || freeSdSpaceNeededToCache < freeSpaceOnSD()){
				 bitmap = getBitmapFormURL(url,type,width,height);
				 return bitmap;
		     }
			 
			 if(type != AbConstant.ORIGINALIMG && ( width<=0 || height<=0)){
				 throw new IllegalArgumentException("縮放和裁剪圖片的寬高設定不能小於0");
			 }
			 
			 //快取的key,也是檔名
			 String key =  AbImageCache.getCacheKey(url, width, height, type);
			 
			 //檔案是否存在
			 File path = Environment.getExternalStorageDirectory();
			 File fileDirectory = new File(path.getAbsolutePath() + downPathImageDir);
			 
			 //獲取字尾
			 String suffix = getSuffixFromNetUrl(url);
			 
			 //快取的圖片檔名
			 String fileName = key+suffix;
			 File file = new File(fileDirectory,fileName);
			 
			 //檢查檔案快取中是否存在檔案
			 File fileCache = AbFileCache.getFileFromCache(fileName);
			 if(fileCache == null){
				 String downFilePath = downFileToSD(url,file.getName());
				 if(downFilePath != null){
					 //下載成功後存入快取
					 AbFileCache.addFileToCache(fileName, file);
					 //獲取
					 return getBitmapFromSD(file,type,width,height);
				 }else{
					 return null;
				 }
			 }else{
				 bitmap = getBitmapFromSD(file,type,width,height);
				 if(D) Log.d(TAG, "從SD快取中得到圖片:"+key+","+bitmap);
				 //獲取
				 return bitmap;
			 }
			 
		} catch (Exception e) {
			e.printStackTrace();
		}
		return bitmap;
		
	 }
過程類似上面,先看sdcard上有沒有,有的話直接載入,沒有的話從網上載入,然後加入快取,這應該還是我們都能想到的思路,getBitmapFormURL其實最終就是通過UrlConnection開啟輸入流讀取圖片,大家肯定很清楚了。鑑於很多地方註釋已經寫得很詳細了,我就不過多地解釋了,希望這次的分析(其實也不叫分析,就是把我認為好的程式碼拿出來分享,)能給大家帶來一點幫助,求各路大神多加點評,多多指導微笑