From 1967de12db7f17dcbe7cd8be00b43eccd50229d9 Mon Sep 17 00:00:00 2001 From: ServeMe Date: Wed, 31 Dec 2014 21:04:07 +0200 Subject: [PATCH 1/2] Fix synchronizition issue NetworkImageView have a problem when it works with cache senario image1 and image2 Respectively image2 available on cache and image1 not available what was happened is fetching imag1 from internet imag2 fetched fast from cache after finish loading image1 it sets over image2 and the last result imag1 and url of image2 -mImageContainer- --- .../volley/toolbox/NetworkImageView.java | 179 ++++++++++-------- 1 file changed, 96 insertions(+), 83 deletions(-) diff --git a/src/main/java/com/android/volley/toolbox/NetworkImageView.java b/src/main/java/com/android/volley/toolbox/NetworkImageView.java index ee248103..d45e2e6f 100644 --- a/src/main/java/com/android/volley/toolbox/NetworkImageView.java +++ b/src/main/java/com/android/volley/toolbox/NetworkImageView.java @@ -18,6 +18,7 @@ import android.content.Context; import android.text.TextUtils; import android.util.AttributeSet; +import android.util.Log; import android.view.ViewGroup.LayoutParams; import android.widget.ImageView; @@ -48,6 +49,9 @@ public class NetworkImageView extends ImageView { /** Current ImageContainer. (either in-flight or finished) */ private ImageContainer mImageContainer; + + // fix synchronization issue + private Object dummyToSynchronize = new Object(); public NetworkImageView(Context context) { this(context, null); @@ -110,89 +114,98 @@ public void setErrorImageResId(int errorImage) { * 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. */ - void loadImageIfNecessary(final boolean isInLayoutPass) { - int width = getWidth(); - int height = getHeight(); - - boolean wrapWidth = false, wrapHeight = false; - if (getLayoutParams() != null) { - wrapWidth = getLayoutParams().width == LayoutParams.WRAP_CONTENT; - wrapHeight = getLayoutParams().height == LayoutParams.WRAP_CONTENT; - } - - // if the view's bounds aren't known yet, and this is not a wrap-content/wrap-content - // view, hold off on loading the image. - boolean isFullyWrapContent = wrapWidth && wrapHeight; - if (width == 0 && height == 0 && !isFullyWrapContent) { - return; - } - - // if the URL to be loaded in this view is empty, cancel any old requests and clear the - // currently loaded image. - if (TextUtils.isEmpty(mUrl)) { - if (mImageContainer != null) { - mImageContainer.cancelRequest(); - mImageContainer = null; - } - setDefaultImageOrNull(); - return; - } - - // if there was an old request in this view, check if it needs to be canceled. - if (mImageContainer != null && mImageContainer.getRequestUrl() != null) { - if (mImageContainer.getRequestUrl().equals(mUrl)) { - // if the request is from the same URL, return. - return; - } else { - // if there is a pre-existing request, cancel it if it's fetching a different URL. - mImageContainer.cancelRequest(); - setDefaultImageOrNull(); - } - } - - // Calculate the max image width / height to use while ignoring WRAP_CONTENT dimens. - int maxWidth = wrapWidth ? 0 : width; - int maxHeight = wrapHeight ? 0 : height; - - // 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); - } - } - }, maxWidth, maxHeight); - - // update the ImageContainer to be the new bitmap container. - mImageContainer = newContainer; - } - + private void loadImageIfNecessary(final boolean isInLayoutPass) { + int width = getWidth(); + int height = getHeight(); + + boolean isFullyWrapContent = getLayoutParams() != null + && getLayoutParams().height == LayoutParams.WRAP_CONTENT + && getLayoutParams().width == LayoutParams.WRAP_CONTENT; + // if the view's bounds aren't known yet, and this is not a + // wrap-content/wrap-content + // view, hold off on loading the image. + if (width == 0 && height == 0 && !isFullyWrapContent) { + return; + } + synchronized (dummyToSynchronize) { + + // if the URL to be loaded in this view is empty, cancel any old + // requests and clear the + // currently loaded image. + + if (TextUtils.isEmpty(mUrl)) { + if (mImageContainer != null) { + mImageContainer.cancelRequest(); + mImageContainer = null; + } + setDefaultImageOrNull(); + return; + } + + // if there was an old request in this view, check if it needs to be + // canceled. + if (mImageContainer != null + && mImageContainer.getRequestUrl() != null) { + if (mImageContainer.getRequestUrl().equals(mUrl)) { + // if the request is from the same URL, return. + return; + } else { + Log.d("urls", mImageContainer.getRequestUrl() + " new " + + mUrl); + // if there is a pre-existing request, cancel it if it's + // fetching a different URL. + mImageContainer.cancelRequest(); + setDefaultImageOrNull(); + } + } + } + + // 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; + } + synchronized (dummyToSynchronize) { + if (response == mImageContainer) + if (response.getBitmap() != null) { + setImageBitmap(response.getBitmap()); + } else if (mDefaultImageId != 0) { + setImageResource(mDefaultImageId); + } + } + } + }); + + // update the ImageContainer to be the new bitmap container. + mImageContainer = newContainer; + } + private void setDefaultImageOrNull() { if(mDefaultImageId != 0) { setImageResource(mDefaultImageId); From dd68cef30de16eadf54454e12697726b7356e705 Mon Sep 17 00:00:00 2001 From: ServeMe Date: Wed, 31 Dec 2014 21:07:07 +0200 Subject: [PATCH 2/2] remove log --- src/main/java/com/android/volley/toolbox/NetworkImageView.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/com/android/volley/toolbox/NetworkImageView.java b/src/main/java/com/android/volley/toolbox/NetworkImageView.java index d45e2e6f..d07401e7 100644 --- a/src/main/java/com/android/volley/toolbox/NetworkImageView.java +++ b/src/main/java/com/android/volley/toolbox/NetworkImageView.java @@ -18,7 +18,6 @@ import android.content.Context; import android.text.TextUtils; import android.util.AttributeSet; -import android.util.Log; import android.view.ViewGroup.LayoutParams; import android.widget.ImageView; @@ -150,8 +149,6 @@ && getLayoutParams().height == LayoutParams.WRAP_CONTENT // if the request is from the same URL, return. return; } else { - Log.d("urls", mImageContainer.getRequestUrl() + " new " - + mUrl); // if there is a pre-existing request, cancel it if it's // fetching a different URL. mImageContainer.cancelRequest();