NetworkImageView で画像のダウンロードを開始するのが loadImageIfNecessary() です。
https://android.googlesource.com/platform/frameworks/volley/+/master/src/com/android/volley/toolbox/NetworkImageView.java
- public class NetworkImageView extends ImageView {
- ...
- /** Local copy of the ImageLoader. */
- private ImageLoader mImageLoader;
- ...
- public void setImageUrl(String url, ImageLoader imageLoader) {
- mUrl = url;
- mImageLoader = imageLoader;
- // The URL has potentially changed. See if we need to load it.
- loadImageIfNecessary(false);
- }
- ...
- /**
- * Loads the image for the view if it isn't already loaded.
- * @param isInLayoutPass True if this was invoked from a layout pass, false otherwise.
- */
- private void loadImageIfNecessary(final boolean isInLayoutPass) {
- ...
- // The pre-existing content of this view didn't match the current URL. Load the new image
- // from the network.
- ImageContainer newContainer = 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 this was an immediate response that was delivered inside of a layout
- // pass do not set the image immediately as it will trigger a requestLayout
- // inside of a layout. Instead, defer setting the image by posting back to
- // the main thread.
- 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);
- }
- }
- });
- // update the ImageContainer to be the new bitmap container.
- mImageContainer = newContainer;
- }
- ...
- }
ImageLoader には引数が4つの get(url, imageLoader, maxWidth, maxHeight) もあり、引数が2つの get() を呼んだ場合は、maxWidth, maxHeight には 0 が渡され、生成される Bitmap は実際の画像サイズになります。
- public class ImageLoader {
- ...
- public ImageContainer get(String requestUrl, final ImageListener listener) {
- return get(requestUrl, listener, 0, 0);
- }
- public ImageContainer get(String requestUrl, ImageListener imageListener,
- int maxWidth, int maxHeight) {
- // only fulfill requests that were initiated from the main thread.
- throwIfNotOnMainThread();
- final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight);
- // Try to look up the request in the cache of remote images.
- Bitmap cachedBitmap = mCache.getBitmap(cacheKey);
- if (cachedBitmap != null) {
- // Return the cached bitmap.
- ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, null, null);
- imageListener.onResponse(container, true);
- return container;
- }
- // The bitmap did not exist in the cache, fetch it!
- ImageContainer imageContainer =
- new ImageContainer(null, requestUrl, cacheKey, imageListener);
- // Update the caller to let them know that they should use the default bitmap.
- imageListener.onResponse(imageContainer, true);
- // Check to see if a request is already in-flight.
- BatchedImageRequest request = mInFlightRequests.get(cacheKey);
- if (request != null) {
- // If it is, add this request to the list of listeners.
- request.addContainer(imageContainer);
- return imageContainer;
- }
- // The request is not already in flight. Send the new request to the network and
- // track it.
- Request<?> newRequest =
- new ImageRequest(requestUrl, new Listener<Bitmap>() {
- @Override
- public void onResponse(Bitmap response) {
- onGetImageSuccess(cacheKey, response);
- }
- }, maxWidth, maxHeight,
- Config.RGB_565, new ErrorListener() {
- @Override
- public void onErrorResponse(VolleyError error) {
- onGetImageError(cacheKey, error);
- }
- });
- mRequestQueue.add(newRequest);
- mInFlightRequests.put(cacheKey,
- new BatchedImageRequest(newRequest, imageContainer));
- return imageContainer;
- }
- }
- public class ImageRequest extends Request<Bitmap> {
- ...
- private final int mMaxWidth;
- private final int mMaxHeight;
- ...
- public ImageRequest(String url, Response.Listener<Bitmap> listener, int maxWidth, int maxHeight,
- Config decodeConfig, Response.ErrorListener errorListener) {
- super(Method.GET, url, errorListener);
- setRetryPolicy(
- new DefaultRetryPolicy(IMAGE_TIMEOUT_MS, IMAGE_MAX_RETRIES, IMAGE_BACKOFF_MULT));
- mListener = listener;
- mDecodeConfig = decodeConfig;
- mMaxWidth = maxWidth;
- mMaxHeight = maxHeight;
- }
- ...
- /**
- * The real guts of parseNetworkResponse. Broken out for readability.
- */
- private Response<Bitmap> 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 {
- // If we have to resize this image, first get the natural bounds.
- decodeOptions.inJustDecodeBounds = true;
- BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);
- int actualWidth = decodeOptions.outWidth;
- int actualHeight = decodeOptions.outHeight;
- // Then compute the dimensions we would ideally like to decode to.
- int desiredWidth = getResizedDimension(mMaxWidth, mMaxHeight,
- actualWidth, actualHeight);
- int desiredHeight = getResizedDimension(mMaxHeight, mMaxWidth,
- actualHeight, actualWidth);
- // Decode to the nearest power of two scaling factor.
- decodeOptions.inJustDecodeBounds = false;
- // TODO(ficus): Do we need this or is it okay since API 8 doesn't support it?
- // decodeOptions.inPreferQualityOverSpeed = PREFER_QUALITY_OVER_SPEED;
- decodeOptions.inSampleSize =
- findBestSampleSize(actualWidth, actualHeight, desiredWidth, desiredHeight);
- Bitmap tempBitmap =
- BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);
- // If necessary, scale down to the maximal acceptable size.
- if (tempBitmap != null && (tempBitmap.getWidth() > desiredWidth ||
- tempBitmap.getHeight() > desiredHeight)) {
- bitmap = Bitmap.createScaledBitmap(tempBitmap,
- desiredWidth, desiredHeight, true);
- tempBitmap.recycle();
- } else {
- bitmap = tempBitmap;
- }
- }
- if (bitmap == null) {
- return Response.error(new ParseError(response));
- } else {
- return Response.success(bitmap, HttpHeaderParser.parseCacheHeaders(response));
- }
- }
- }
それ以外のときは BitmapFactory.Options の inJustDecodeBounds や inSampleSize を使って Bitmap をスケールしています。
以下では、View のサイズがわかっている場合はそのサイズを使い、わからないときは画面サイズを指定するようにしてみました。
- public class NetworkImageView extends ImageView {
- ...
- private void loadImageIfNecessary(final boolean isInLayoutPass) {
- int width = getWidth();
- int height = getHeight();
- ...
- DisplayMetrics metrics = getResources().getDisplayMetrics();
- int w = width > 0 ? width : metrics.widthPixels;
- int h = height > 0 ? height : metrics.heightPixels;
- // The pre-existing content of this view didn't match the current URL. Load the new image
- // from the network.
- ImageContainer newContainer = 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 this was an immediate response that was delivered inside of a layout
- // pass do not set the image immediately as it will trigger a requestLayout
- // inside of a layout. Instead, defer setting the image by posting back to
- // the main thread.
- 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);
- }
- }
- }, w, h);
- // update the ImageContainer to be the new bitmap container.
- mImageContainer = newContainer;
- }
- }
0 件のコメント:
コメントを投稿