上一章詳細介紹了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網絡圖片加載部分的理解,有些地方的理解有問題,如果有不對的地方,希望各位大神指點。