Android Volleyソース解析(三)、画像ロードの実現
19325 ワード
前言
前の文章では、Volleyのキャッシュメカニズムを深く探究し、ソース分析を通じてキャッシュの動作原理を理解しました.この文章では、「Volleyピクチャロードの実現」を探究します.ピクチャロードとキャッシュは密接に関連しています.まず、Android Volleyソースコード解析(二)、キャッシュメカニズムを探究することをお勧めします.
これはVolleyソース解析シリーズの最後の文章です.今日は基本的な使い方とソース分析を組み合わせた方法で行います.もちろん、本稿のソースは最初のソース分析に基づいています.まだこの文章を見たことがない友达は、まず読むことをお勧めします.Android Volleyソース解析(一)、ネットワークリクエストの実行プロセスです.
一、画像のロードの基本的な使い方
ソース解析を行う前に、Volleyでのピクチャロードに関する基本的な使い方を見てみましょう.
1.1 ImageRequestの使い方
ImageRequestもStringRequestもJsonRequestもRequestから継承されているため、基本的に同じ使い方をしています.まず、RequestQueueオブジェクトを取得する必要があります.
次にnewはImageRequestオブジェクトを出力します.
ImageRequestは6つのパラメータを受信していることがわかります.
1、画像のURLアドレス
2、画像要求の成功したコールバック、ここで私達は戻ったBitmapをImageViewに設定する
3、4はそれぞれ画像の最大許容幅と高さを指定するために用いられ、指定したネットワーク画像の幅または高さがここの値より大きい場合は画像を圧縮し、0に指定すると、画像がどんなに大きくても圧縮しないことを示す
5、画像の属性を指定し、Bitmap.Configの下のいくつかの定数はすべて使用することができて、その中のARGB_8888は最良の色属性を示すことができ、各ピクチャの画素画素は4バイトを占め、RGB_565は、各ピクチャ画素が2バイトを占めることを示す
6、画像要求に失敗したコールバック
最後にこのImageRequestをRequestQueueに追加すればいいです
1.2 ImageLoaderの使い方
ImageLoaderは、実際にはImageRequestのパッケージであり、画像をキャッシュするだけでなく、重複するリンクをフィルタリングし、重複送信要求を回避することができるため、ImageLoaderはImageRequestよりも効率的です.
ImageLoaderの使い方は、主に次の4つのステップに分けられます.
1.RequestQueueオブジェクトの作成2、ImageLoaderオブジェクトの作成3、ImageListenerオブジェクトの取得4、ImageLoaderを呼び出すget()メソッド記述ピクチャ
ImageLoaderのコンストラクション関数は2つのパラメータを受信していることがわかります.1つ目のパラメータはRequestQueueオブジェクトで、2つ目のパラメータはImageCacheです.ここでは直接newで空のImageCache実装をすればいいです.
ImageListenerには、ロードするピクチャのURLと、ピクチャプレースホルダと、ロードに失敗した後に表示するピクチャが入力され、最後にImageLoaderが呼び出される.get()メソッドで画像のロードができます.
1.3 NetworkImageView
以上の2つの方法に加えて、Volleyは第3の方法でネットワークピクチャをロードすることを提供し、NetworkImageViewはImageViewから継承されたカスタムViewであり、ImageViewに基づいてネットワークピクチャをロードする機能を拡張する.NetworkImageViewの使い方は簡単です.大きく4つのステップに分けられます.
1、RequestQueueオブジェクトの作成2、ImageLoaderオブジェクトの作成3、コードからNetworkImageViewを取得するインスタンス4、ロードするピクチャアドレスの設定
次のようになります.
二、ImageRequestソースコード解析
前節ではVolleyピクチャのロードの3つの方法を紹介しましたが、この節からソースコードを組み合わせてVolleyピクチャのロードの実現を分析し、ImageRequestから始めましょう.
Android Volleyソース解析(一)では,ネットワークリクエストの実行プロセスについて,ネットワークリクエストは最終的にサーバから返された結果をNetworkResponseにカプセル化してRequestに渡して処理すると述べた.ImageRequestの仕事は、NetworkResponseをBitmapを含むResponseに解析し、最後にコールバックすることです.
私たちが分析しなければならないのは、この過程です.
parseNetworkResponseにはdoParse()メソッドが1つしかないことがわかります
doParse()でどのような操作が行われているのか見てみましょう
コードが長いので、5つのステップに分けてみましょう.
①Bitmapオリジナルの幅と高さを取得する
送信NetworkResponseのdataをBitmapFactoryで対応するBitmapに変換し、BitmapOptionsを設定.inJustDecodeBounds=true、Bitmapの元の幅と高さを得て、ここで補足して、BitmapOptions.inJustDecodeBounds=trueのとき、BitmapFactory.decodeは本当にbitmapを返すわけではありません.幅や高さなどの画像のサイズ情報を返すだけで、メモリをあまり消費しません.
②私たちが本当に望んでいる幅と高さを計算する
ImageRequestを構築したときに渡されたパラメータを覚えているでしょう.その6つのパラメータには、画像の最大幅と高さをそれぞれ指定する2つのパラメータが含まれています.私たちは、入力した画像の最大幅と高さ、Bitmapの実際の幅と高さをgetResizedDemension()メソッドで計算し、適切な画像の表示幅を以下のように計算します.
③私たちが望む幅と高さに応じて対応するBitmapを得る
DecodeOptions.inJustDecodeBounds=trueは本当のBitmapを返しますDecodeOptions.inSampleSizeはピクチャのサンプリングレートを表し,ピクチャ圧縮に関するパラメータであり,inSampleSize=2であれば元のピクチャの幅と高さをそれぞれ元の1/2に減少させることを表す.
④Bitmapがbullでなく、目標幅よりも幅または高さが大きい場合は、再度圧縮
⑤得られたBitmapを含むResponseをコールバックする
三、ImageLoaderソースコード解析
ImageLoaderの使い方については、主に4つのステップに分かれています.
1.RequestQueueオブジェクトの作成2、ImageLoaderオブジェクトの作成3、ImageListenerオブジェクトの取得4、ImageLoaderを呼び出すget()メソッドによるピクチャのロード
では、その使い方から始めて、どのように実現されたのかを一歩一歩分析します.
RequestQueueの作成については前述したように、Android Volleyソースコード解析(一)、ネットワークリクエストの実行プロセス、ImageLoaderの構築方法を参照してください.
現在のインスタンスのメンバー変数にRequestQueueとImageCacheを割り当てた構造方法が表示されます.次に、ImageListenerを参照して取得します.ImageListenerはImageLoaderを介して取得されます.getImageListener()メソッド:
ここでは主にコールバックされたBitmapを対応するImageViewに設定し,いくつかのピクチャロードのフォールトトレランス処理を行うことがわかる.
最後に、ImageLoaderのget()メソッドはImageLoaderクラスで最も複雑なメソッドであり、最も核心的なメソッドでもあるので、一緒に見てみましょう.
まず現在のスレッドの判断を行い,メインスレッドでなければ直接エラーを投げ出す.
次に対応するBitmapをキャッシュから取り出し、Bitmapがnullでない場合はImageListenerに直接コールバックして対応するImageViewにBitmapを設定します.
そしてUrlに従ってキャッシュキューからRequestを取り出す
キャッシュにリクエストが見つからない場合は、ネットワークリクエストを1回実行します.
ImageLoaderがmakeImageReqeust()メソッドを呼び出してRequestを構築していることがわかります.彼がどのように実現しているかを見てみましょう.
ネットワーク要求が成功すると、onGetImageSuccess()メソッドを呼び出し、Bitmapをキャッシュし、キャッシュキュー内のcacheKeyに対応するBatchedImageRequestを削除し、最後にbatchResponse()メソッドを呼び出します.
batchResponse()メソッドでは、メインスレッドでBitmapをImageListerにコールバックし、BitmapをImageViewに設定することで、ピクチャロードのすべてのプロセスが完了します.
四、NetworkImageViewソースコード解析
NetworkImageViewは、内部でImageLoaderを使用してネットワークピクチャをロードするカスタムViewです.NetworkImageViewの使用方法は、主に4つのステップに分かれています.
1.RequestQueueオブジェクトを作成する2、ImageLoaderオブジェクトを作成する3、コードからNetworkImageViewのインスタンスを取得する4、setImageUrl()メソッドを呼び出してロードするピクチャアドレスを設定する
最後のステップはNetworkImageViewのコアです.setImageUrl()内部でどのように実現されているかを見てみましょう.
簡単な3行のコードしかないので、主な論理はloadImageIfNecessary()という方法の中にあると思います.
コードは比較的明確で、まずいくつかのフォールトトレランスの処理を行い、ImageLoaderを呼び出して対応するbitmapを取得し、最後にNetworkImageViewに設定.
まとめ
Volleyソース解析シリーズは、ここまでですべて終わりました.これは私が書いた最も長いシリーズの文章です.最初からVolleyソースの読書から、その後のコード整理と今の文章の出力まで、私は1週間もかかりませんでしたが、ネットロードと画像ロードについてもっと理解しました.ここを完全に見ることができるのはすべて本当の爱ですね.ありがとうございました.
関連記事 Android Volleyソースコード解析(一)、ネットワーク要求の実行フロー Android Volleyソースコード解析(二)、キャッシュメカニズム を探究する
前の文章では、Volleyのキャッシュメカニズムを深く探究し、ソース分析を通じてキャッシュの動作原理を理解しました.この文章では、「Volleyピクチャロードの実現」を探究します.ピクチャロードとキャッシュは密接に関連しています.まず、Android Volleyソースコード解析(二)、キャッシュメカニズムを探究することをお勧めします.
これはVolleyソース解析シリーズの最後の文章です.今日は基本的な使い方とソース分析を組み合わせた方法で行います.もちろん、本稿のソースは最初のソース分析に基づいています.まだこの文章を見たことがない友达は、まず読むことをお勧めします.Android Volleyソース解析(一)、ネットワークリクエストの実行プロセスです.
一、画像のロードの基本的な使い方
ソース解析を行う前に、Volleyでのピクチャロードに関する基本的な使い方を見てみましょう.
1.1 ImageRequestの使い方
ImageRequestもStringRequestもJsonRequestもRequestから継承されているため、基本的に同じ使い方をしています.まず、RequestQueueオブジェクトを取得する必要があります.
RequestQueue mQueue = Volley.newRequestQueue(context);
次にnewはImageRequestオブジェクトを出力します.
private static final String URL = "http://ww4.sinaimg.cn/large/610dc034gw1euxdmjl7j7j20r2180wts.jpg";
ImageRequest imageRequest = new ImageRequest(URL, new Response.Listener() {
@Override
public void onResponse(Bitmap response) {
imageView.setImageBitmap(response);
}
}, 0, 0, ImageView.ScaleType.CENTER_CROP, Bitmap.Config.RGB_565, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
});
ImageRequestは6つのパラメータを受信していることがわかります.
1、画像のURLアドレス
2、画像要求の成功したコールバック、ここで私達は戻ったBitmapをImageViewに設定する
3、4はそれぞれ画像の最大許容幅と高さを指定するために用いられ、指定したネットワーク画像の幅または高さがここの値より大きい場合は画像を圧縮し、0に指定すると、画像がどんなに大きくても圧縮しないことを示す
5、画像の属性を指定し、Bitmap.Configの下のいくつかの定数はすべて使用することができて、その中のARGB_8888は最良の色属性を示すことができ、各ピクチャの画素画素は4バイトを占め、RGB_565は、各ピクチャ画素が2バイトを占めることを示す
6、画像要求に失敗したコールバック
最後にこのImageRequestをRequestQueueに追加すればいいです
mQueue.add(imageRequest);
1.2 ImageLoaderの使い方
ImageLoaderは、実際にはImageRequestのパッケージであり、画像をキャッシュするだけでなく、重複するリンクをフィルタリングし、重複送信要求を回避することができるため、ImageLoaderはImageRequestよりも効率的です.
ImageLoaderの使い方は、主に次の4つのステップに分けられます.
1.RequestQueueオブジェクトの作成2、ImageLoaderオブジェクトの作成3、ImageListenerオブジェクトの取得4、ImageLoaderを呼び出すget()メソッド記述ピクチャ
RequestQueue requestQueue = Volley.newRequestQueue(this);
ImageLoader imageLoader = new ImageLoader(requestQueue, new ImageLoader.ImageCache() {
@Override
public Bitmap getBitmap(String url) {
return null;
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
}
});
ImageLoader.ImageListener listener = ImageLoader.getImageListener(mIvShow, R.mipmap.ic_launcher, R.mipmap.ic_launcher_round);
imageLoader.get(URL, listener);
ImageLoaderのコンストラクション関数は2つのパラメータを受信していることがわかります.1つ目のパラメータはRequestQueueオブジェクトで、2つ目のパラメータはImageCacheです.ここでは直接newで空のImageCache実装をすればいいです.
ImageListenerには、ロードするピクチャのURLと、ピクチャプレースホルダと、ロードに失敗した後に表示するピクチャが入力され、最後にImageLoaderが呼び出される.get()メソッドで画像のロードができます.
1.3 NetworkImageView
以上の2つの方法に加えて、Volleyは第3の方法でネットワークピクチャをロードすることを提供し、NetworkImageViewはImageViewから継承されたカスタムViewであり、ImageViewに基づいてネットワークピクチャをロードする機能を拡張する.NetworkImageViewの使い方は簡単です.大きく4つのステップに分けられます.
1、RequestQueueオブジェクトの作成2、ImageLoaderオブジェクトの作成3、コードからNetworkImageViewを取得するインスタンス4、ロードするピクチャアドレスの設定
次のようになります.
RequestQueue requestQueue = Volley.newRequestQueue(this);
ImageLoader imageLoader = new ImageLoader(requestQueue, new ImageLoader.ImageCache() {
@Override
public Bitmap getBitmap(String url) {
return null;
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
}
});
networkImageView.setImageUrl(URL, imageLoader);
二、ImageRequestソースコード解析
前節ではVolleyピクチャのロードの3つの方法を紹介しましたが、この節からソースコードを組み合わせてVolleyピクチャのロードの実現を分析し、ImageRequestから始めましょう.
Android Volleyソース解析(一)では,ネットワークリクエストの実行プロセスについて,ネットワークリクエストは最終的にサーバから返された結果をNetworkResponseにカプセル化してRequestに渡して処理すると述べた.ImageRequestの仕事は、NetworkResponseをBitmapを含むResponseに解析し、最後にコールバックすることです.
私たちが分析しなければならないのは、この過程です.
parseNetworkResponseにはdoParse()メソッドが1つしかないことがわかります
@Override
protected Response parseNetworkResponse(NetworkResponse response) {
synchronized (sDecodeLock) {
try {
return doParse(response);
} catch (OutOfMemoryError e) {
return Response.error(new ParseError(e));
}
}
}
doParse()でどのような操作が行われているのか見てみましょう
private Response doParse(NetworkResponse response) {
byte[] data = response.data;
BitmapFactory.Options decodeOptions = new BitmapFactory.Options();
Bitmap bitmap = null;
if (mMaxWidth == 0 && mMaxHeight == 0) {
decodeOptions.inPreferredConfig = mDecodeConfig;
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);
} else {
// ① Bitmap
decodeOptions.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);
int actualWidth = decodeOptions.outWidth;
int actualHeight = decodeOptions.outHeight;
// ②
int desiredWidth = getResizedDimension(mMaxWidth, mMaxHeight,
actualWidth, actualHeight, mScaleType);
int desiredHeight = getResizedDimension(mMaxHeight, mMaxWidth,
actualHeight, actualWidth, mScaleType);
// ③ Bitmap
decodeOptions.inJustDecodeBounds = false;
decodeOptions.inSampleSize =
findBestSampleSize(actualWidth, actualHeight, desiredWidth, desiredHeight);
Bitmap tempBitmap =
BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);
// ④ Bitmap bull ,
if (tempBitmap != null && (tempBitmap.getWidth() > desiredWidth ||
tempBitmap.getHeight() > desiredHeight)) {
bitmap = Bitmap.createScaledBitmap(tempBitmap,
desiredWidth, desiredHeight, true);
tempBitmap.recycle();
} else {
bitmap = tempBitmap;
}
}
// ⑤ Bitmap Response
if (bitmap == null) {
return Response.error(new ParseError(response));
} else {
return Response.success(bitmap, HttpHeaderParser.parseCacheHeaders(response));
}
}
コードが長いので、5つのステップに分けてみましょう.
①Bitmapオリジナルの幅と高さを取得する
送信NetworkResponseのdataをBitmapFactoryで対応するBitmapに変換し、BitmapOptionsを設定.inJustDecodeBounds=true、Bitmapの元の幅と高さを得て、ここで補足して、BitmapOptions.inJustDecodeBounds=trueのとき、BitmapFactory.decodeは本当にbitmapを返すわけではありません.幅や高さなどの画像のサイズ情報を返すだけで、メモリをあまり消費しません.
②私たちが本当に望んでいる幅と高さを計算する
ImageRequestを構築したときに渡されたパラメータを覚えているでしょう.その6つのパラメータには、画像の最大幅と高さをそれぞれ指定する2つのパラメータが含まれています.私たちは、入力した画像の最大幅と高さ、Bitmapの実際の幅と高さをgetResizedDemension()メソッドで計算し、適切な画像の表示幅を以下のように計算します.
private static int getResizedDimension(int maxPrimary, int maxSecondary, int actualPrimary,
int actualSecondary, ScaleType scaleType) {
if ((maxPrimary == 0) && (maxSecondary == 0)) {
return actualPrimary;
}
if (maxPrimary == 0) {
double ratio = (double) maxSecondary / (double) actualSecondary;
return (int) (actualPrimary * ratio);
}
if (maxSecondary == 0) {
return maxPrimary;
}
double ratio = (double) actualSecondary / (double) actualPrimary;
int resized = maxPrimary;
if (scaleType == ScaleType.CENTER_CROP) {
if ((resized * ratio) < maxSecondary) {
resized = (int) (maxSecondary / ratio);
}
return resized;
}
if ((resized * ratio) > maxSecondary) {
resized = (int) (maxSecondary / ratio);
}
return resized;
}
③私たちが望む幅と高さに応じて対応するBitmapを得る
DecodeOptions.inJustDecodeBounds=trueは本当のBitmapを返しますDecodeOptions.inSampleSizeはピクチャのサンプリングレートを表し,ピクチャ圧縮に関するパラメータであり,inSampleSize=2であれば元のピクチャの幅と高さをそれぞれ元の1/2に減少させることを表す.
decodeOptions.inJustDecodeBounds = false;
decodeOptions.inSampleSize =
findBestSampleSize(actualWidth, actualHeight, desiredWidth, desiredHeight);
Bitmap tempBitmap =
BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);
//
static int findBestSampleSize(
int actualWidth, int actualHeight, int desiredWidth, int desiredHeight) {
double wr = (double) actualWidth / desiredWidth;
double hr = (double) actualHeight / desiredHeight;
double ratio = Math.min(wr, hr);
float n = 1.0f;
while ((n * 2) <= ratio) {
n *= 2;
}
return (int) n;
}
④Bitmapがbullでなく、目標幅よりも幅または高さが大きい場合は、再度圧縮
if (tempBitmap != null && (tempBitmap.getWidth() > desiredWidth ||
tempBitmap.getHeight() > desiredHeight)) {
bitmap = Bitmap.createScaledBitmap(tempBitmap,
desiredWidth, desiredHeight, true);
tempBitmap.recycle();
} else {
bitmap = tempBitmap;
}
⑤得られたBitmapを含むResponseをコールバックする
if (bitmap == null) {
return Response.error(new ParseError(response));
} else {
return Response.success(bitmap, HttpHeaderParser.parseCacheHeaders(response));
}
三、ImageLoaderソースコード解析
ImageLoaderの使い方については、主に4つのステップに分かれています.
1.RequestQueueオブジェクトの作成2、ImageLoaderオブジェクトの作成3、ImageListenerオブジェクトの取得4、ImageLoaderを呼び出すget()メソッドによるピクチャのロード
では、その使い方から始めて、どのように実現されたのかを一歩一歩分析します.
RequestQueueの作成については前述したように、Android Volleyソースコード解析(一)、ネットワークリクエストの実行プロセス、ImageLoaderの構築方法を参照してください.
public ImageLoader(RequestQueue queue, ImageCache imageCache) {
mRequestQueue = queue;
mCache = imageCache;
}
現在のインスタンスのメンバー変数にRequestQueueとImageCacheを割り当てた構造方法が表示されます.次に、ImageListenerを参照して取得します.ImageListenerはImageLoaderを介して取得されます.getImageListener()メソッド:
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);
}
}
};
}
ここでは主にコールバックされたBitmapを対応するImageViewに設定し,いくつかのピクチャロードのフォールトトレランス処理を行うことがわかる.
最後に、ImageLoaderのget()メソッドはImageLoaderクラスで最も複雑なメソッドであり、最も核心的なメソッドでもあるので、一緒に見てみましょう.
public ImageContainer get(String requestUrl, ImageListener imageListener,
int maxWidth, int maxHeight, ScaleType scaleType) {
// (UI )
throwIfNotOnMainThread();
final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight, scaleType);
// Bitmap, Bitmap null, imageListener Bitmap ImageView
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 newRequest = makeImageRequest(requestUrl, maxWidth, maxHeight, scaleType,
cacheKey);
mRequestQueue.add(newRequest);
//
mInFlightRequests.put(cacheKey,
new BatchedImageRequest(newRequest, imageContainer));
return imageContainer;
}
まず現在のスレッドの判断を行い,メインスレッドでなければ直接エラーを投げ出す.
private void throwIfNotOnMainThread() {
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException("ImageLoader must be invoked from the main thread.");
}
}
次に対応するBitmapをキャッシュから取り出し、Bitmapがnullでない場合はImageListenerに直接コールバックして対応するImageViewにBitmapを設定します.
Bitmap cachedBitmap = mCache.getBitmap(cacheKey);
if (cachedBitmap != null) {
ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, null, null);
imageListener.onResponse(container, true);
return container;
}
そしてUrlに従ってキャッシュキューからRequestを取り出す
BatchedImageRequest request = mInFlightRequests.get(cacheKey);
if (request != null) {
request.addContainer(imageContainer);
return imageContainer;
}
キャッシュにリクエストが見つからない場合は、ネットワークリクエストを1回実行します.
Request newRequest = makeImageRequest(requestUrl, maxWidth, maxHeight, scaleType,
cacheKey);
ImageLoaderがmakeImageReqeust()メソッドを呼び出してRequestを構築していることがわかります.彼がどのように実現しているかを見てみましょう.
protected Request makeImageRequest(String requestUrl, int maxWidth, int maxHeight,
ScaleType scaleType, final String cacheKey) {
return new ImageRequest(requestUrl, new Listener() {
@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()メソッドを呼び出し、Bitmapをキャッシュし、キャッシュキュー内のcacheKeyに対応するBatchedImageRequestを削除し、最後にbatchResponse()メソッドを呼び出します.
protected void onGetImageSuccess(String cacheKey, Bitmap response) {
mCache.putBitmap(cacheKey, response);
BatchedImageRequest request = mInFlightRequests.remove(cacheKey);
if (request != null) {
request.mResponseBitmap = response;
batchResponse(cacheKey, request);
}
}
batchResponse()メソッドでは、メインスレッドでBitmapをImageListerにコールバックし、BitmapをImageViewに設定することで、ピクチャロードのすべてのプロセスが完了します.
private void batchResponse(String cacheKey, BatchedImageRequest request) {
mBatchedResponses.put(cacheKey, request);
if (mRunnable == null) {
mRunnable = new Runnable() {
@Override
public void run() {
for (BatchedImageRequest bir : mBatchedResponses.values()) {
for (ImageContainer container : bir.mContainers) {
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;
}
};
mHandler.postDelayed(mRunnable, mBatchResponseDelayMs);
}
}
四、NetworkImageViewソースコード解析
NetworkImageViewは、内部でImageLoaderを使用してネットワークピクチャをロードするカスタムViewです.NetworkImageViewの使用方法は、主に4つのステップに分かれています.
1.RequestQueueオブジェクトを作成する2、ImageLoaderオブジェクトを作成する3、コードからNetworkImageViewのインスタンスを取得する4、setImageUrl()メソッドを呼び出してロードするピクチャアドレスを設定する
最後のステップはNetworkImageViewのコアです.setImageUrl()内部でどのように実現されているかを見てみましょう.
public void setImageUrl(String url, ImageLoader imageLoader) {
mUrl = url;
mImageLoader = imageLoader;
loadImageIfNecessary(false);
}
簡単な3行のコードしかないので、主な論理はloadImageIfNecessary()という方法の中にあると思います.
void loadImageIfNecessary(final boolean isInLayoutPass) {
// URL null,
if (TextUtils.isEmpty(mUrl)) {
if (mImageContainer != null) {
mImageContainer.cancelRequest();
mImageContainer = null;
}
setDefaultImageOrNull();
return;
}
// NetworkImageView setImageUrl(),
// Url URL
if (mImageContainer != null && mImageContainer.getRequestUrl() != null) {
if (mImageContainer.getRequestUrl().equals(mUrl)) {
return;
} else {
mImageContainer.cancelRequest();
setDefaultImageOrNull();
}
}
// ImageLoader
mImageContainer = mImageLoader.get(mUrl,
new ImageListener() {
@Override
public void onErrorResponse(VolleyError error) {
if (mErrorImageId != 0) {
setImageResource(mErrorImageId);
}
}
@Override
public void onResponse(final ImageContainer response, boolean isImmediate) {
if (isImmediate && isInLayoutPass) {
post(new Runnable() {
@Override
public void run() {
onResponse(response, false);
}
});
return;
}
if (response.getBitmap() != null) {
setImageBitmap(response.getBitmap());
} else if (mDefaultImageId != 0) {
setImageResource(mDefaultImageId);
}
}
}, maxWidth, maxHeight, scaleType);
}
コードは比較的明確で、まずいくつかのフォールトトレランスの処理を行い、ImageLoaderを呼び出して対応するbitmapを取得し、最後にNetworkImageViewに設定.
まとめ
Volleyソース解析シリーズは、ここまでですべて終わりました.これは私が書いた最も長いシリーズの文章です.最初からVolleyソースの読書から、その後のコード整理と今の文章の出力まで、私は1週間もかかりませんでしたが、ネットロードと画像ロードについてもっと理解しました.ここを完全に見ることができるのはすべて本当の爱ですね.ありがとうございました.
関連記事