Volley源碼解析(三)——圖片加載

上一章詳細介紹了volley網絡請求的流程,這一章將會介紹一下volley圖片加載部分源碼分析。
Volley還可以進行圖片的加載和緩存,可以利用ImageRequest對象簡單、方便地進行網絡圖片的獲取。ImageLoader用於獲取或緩存圖片。NetworkImageView是Volley提供的一個自定義View,可直接設置網絡圖片。

1、使用ImageRequest進行網絡圖片獲取
使用方法如下:

ImageRequest request = new ImageRequest(url, new Response.Listener<Bitmap>() {    
    @Override    
    public void onResponse(Bitmap response) {  
        //給imageView設置圖片      
        myImageView.setImageBitmap(response);    
    }
}, 0, 0, ImageView.ScaleType.CENTER, Bitmap.Config.RGB_565, new Response.ErrorListener() {    
    @Override    
    public void onErrorResponse(VolleyError error) { 
          //設置一張錯誤的圖片,臨時用ic_launcher代替          
                   myImageView.setImageResource(R.drawable.ic_launcher);    
   }
}); 

然後再將ImageRequest加入到RequestQueue隊列中,進行網絡請求,傳入一些參數:
String : 要獲取的圖片地址
Response.Listener : 獲取圖片成功的回調
int: maxWidth,獲取圖片的最大寬度,會自動進行壓縮或拉伸,設置爲0,即獲取原圖
int :maxHeight,同上
ScaleType :顯示的類型,居中,平鋪等
Config:圖片類型,如:Bitmap.Config.RGB_565
Response.ErrorListener: 獲取圖片失敗的回調

2、使用ImageLoader緩存網絡圖片
使用imageloader需要以下三步驟,我們從使用方法來看一下源碼實現。

2.1 實例化ImageLoader

ImageLoader loader = new ImageLoader(requestQueue, new BitmapCache());

requestQueue是前面講過的請求隊列,BitmapCache是一個接口,需要我們自定義imageCache對象。我們可以使用LruCache作爲圖片緩存對象,如下:

public class BitmapCache implements ImageLoader.ImageCache {    
  private LruCache<String, Bitmap> lruCache ;    
  private int max = 10*1024*1024;    

   public BitmapCache(){       
     lruCache = new LruCache<String, Bitmap>(max){            
      @Override            
      protected int sizeOf(String key, Bitmap value) {                
         return value.getRowBytes()*value.getHeight();            
      }        
     };    
   }   
   @Override    
   public Bitmap getBitmap(String url) {        
      return lruCache.get(url);    
   }    
   @Override    
   public void putBitmap(String url, Bitmap bitmap) {          
      lruCache.put(url, bitmap);    
   }
}

2.2 設置監聽器

ImageLoader.ImageListener listener = 
         ImageLoader.getImageListener(myImageView, R.drawable.ic_launcher, R.drawable.ic_launcher);

我們看一下ImageLoader.java中的ImageListener函數。

 public static ImageListener getImageListener(final ImageView view,
            final int defaultImageResId, final int errorImageResId) {
        return new ImageListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                if (errorImageResId != 0) {
                    view.setImageResource(errorImageResId);
                }
            }

            @Override
            public void onResponse(ImageContainer response, boolean isImmediate) {
                if (response.getBitmap() != null) {
                    view.setImageBitmap(response.getBitmap());
                } else if (defaultImageResId != 0) {
                    view.setImageResource(defaultImageResId);
                }
            }
        };
    }

就是返回一個ImageListener,裏面定義了ImageListener接口。

2.3 獲取圖片

loader.get(url, listener);

我們看一下源碼imageloader中的get函數

throwIfNotOnMainThread();

   final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight, scaleType);
   Bitmap cachedBitmap = mCache.getBitmap(cacheKey);
   if (cachedBitmap != null) {
           ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, null, null);
            imageListener.onResponse(container, true);
            return container;
        }

       ImageContainer imageContainer =
                new ImageContainer(null, requestUrl, cacheKey, imageListener);
       imageListener.onResponse(imageContainer, true);
       BatchedImageRequest request = mInFlightRequests.get(cacheKey);
        if (request != null) {
            request.addContainer(imageContainer);
            return imageContainer;
        }

        Request<Bitmap> newRequest = makeImageRequest(requestUrl, maxWidth, maxHeight, scaleType,
                cacheKey);

        mRequestQueue.add(newRequest);
        mInFlightRequests.put(cacheKey,
                new BatchedImageRequest(newRequest, imageContainer));
        return imageContainer;

我們將這些源碼分解開來看。

2.3.1

 final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight, scaleType);
   Bitmap cachedBitmap = mCache.getBitmap(cacheKey);
   if (cachedBitmap != null) {
           ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, null, null);
            imageListener.onResponse(container, true);
            return container;
        }

這段代碼,我們先看一下緩存中有沒有我們自定義的getBitmap圖片,就是我們上面自定義的BitmapCache,上面我使用的是LruCache。如果緩存中有我們要網絡加載的圖片的話,即cachedBitmap != null,我們就可以回調,顯示出來啦。

2.3.2

 BatchedImageRequest request = mInFlightRequests.get(cacheKey);
        if (request != null) {
            request.addContainer(imageContainer);
            return imageContainer;
        }

判斷一下請求是否在請求隊列中,如果在就直接return。

2.3.3

Request<Bitmap> newRequest = makeImageRequest(requestUrl, maxWidth, maxHeight, scaleType,  cacheKey);

        mRequestQueue.add(newRequest);
        mInFlightRequests.put(cacheKey,
                new BatchedImageRequest(newRequest, imageContainer));
        return imageContainer;

如果不在隊列和緩存中,就要就要request加入到網絡請求中,關鍵函數就是makeImageRequest,我們看一下源碼。

return new ImageRequest(requestUrl, new Listener<Bitmap>() {
            @Override
            public void onResponse(Bitmap response) {
                onGetImageSuccess(cacheKey, response);
            }
        }, maxWidth, maxHeight, scaleType, Config.RGB_565, new ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                onGetImageError(cacheKey, error);
            }
        });

這就是網絡請求,返回數據處理,看一下onGetImageSuccess函數。

  // 放到緩存中
        mCache.putBitmap(cacheKey, response);

        // 從請求隊列中remove掉
        BatchedImageRequest request = mInFlightRequests.remove(cacheKey);

        if (request != null) {
             request.mResponseBitmap = response;
             batchResponse(cacheKey, request);
        }

我們在看一下batchResponse函數。

mBatchedResponses.put(cacheKey, request);
   // If we don't already have a batch delivery runnable in flight, make a new one.
  // Note that this will be used to deliver responses to all callers in mBatchedResponses.
        if (mRunnable == null) {
            mRunnable = new Runnable() {
                @Override
                public void run() {
                    for (BatchedImageRequest bir : mBatchedResponses.values()) {
                        for (ImageContainer container : bir.mContainers) {
                            // If one of the callers in the batched request canceled the request
                            // after the response was received but before it was delivered,
                            // skip them.
                            if (container.mListener == null) {
                                continue;
                            }
                            if (bir.getError() == null) {
                                container.mBitmap = bir.mResponseBitmap;
                                container.mListener.onResponse(container, false);
                            } else {
                                container.mListener.onErrorResponse(bir.getError());
                            }
                        }
                    }
                    mBatchedResponses.clear();
                    mRunnable = null;
                }

            };
            // Post the runnable.
            mHandler.postDelayed(mRunnable, mBatchResponseDelayMs);
        }

請求隊列循環,當container.mListener != null並且bir.getError() == null,就可以回調container.mListener.onResponse(container, false)函數,然後這個線程每隔100ms執行一次。

volley圖片加載部分到這裏就結束了,但我還是沒有找到圖片網絡請求具體部分在哪裏,這是我對volley網絡圖片加載部分的理解,有些地方的理解有問題,如果有不對的地方,希望各位大神指點。

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