【第三篇】Volley图片加载之NetworkImageView代码分析

Volley的使用之加载图片讲过使用NetWorkImageView进行图片加载的例子,本文着重讲解NetWorkImageView内部是如何实现的,以及Volley这个控件有什么特性。
 
1,通过几个构造方法,可见NetworkImageView并没有添加自己的自定义属性,而是继承自Imageview的自定义属性。
 
2,然后是setImageUrl(String url,ImageLoader imageLoader),第一个参数为网络图片url,第二个参数为Imageloader对象,一般我们在开发过程中会如下使用NetWorkImageView。
1         load_img =(NetworkImageView) findViewById(R.id.load_img);
2         lruImageCache =LruImageCache.getInstance();
3         requestQueue =Volley.newRequestQueue(this);
4         imageLoader =newImageLoader(requestQueue, lruImageCache);
5         load_img.setImageUrl(IMGURL, imageLoader);

 

其中setImageUrl方法中会去调用loadImageIfNecessary(false)方法;那就着重看下这个方法:
第 73行,74行,获取当前NetWorkImageView的组件宽高;
 
第91行到98行,如何传进来的url为null,就会取消图片加载请求,并设置默认的图片给NetWorkImageView;
 
调用155-166行代码,mDefaultImageId是通过setDefaultImageResId(int defaultImage)方法传递进来的,(由此可以可以看出,有必要设置一个默认的图片在NetWorkImageView中,防止在图片url为null的情况下的不友好的界面显示效果),否则调用ImagView的setImageBitmap(null)代码;
 
100-111行代码是判断是否该NetworkImageView重复调用过该图片url,如果重复调用return掉,如果现在调用的图片url和以前的图片url不同,cannel掉以前的图片加载,并设置默认的图片给该NetworkImageView。
 
mImageLoader.get方法其实要穿进去组件的宽高,里面有两个回调函数,分别处理加载成功和加载失败情况下的问题处理,如果失败调用onErrorResponse,否则调用onResponse,表示获取图片的相关信息了,然后看失败里面调用的是setErrorImageResId(int errorImage),其实这个图片也是可以从外面通过参数设置在加载图片失败的情况下的图片显示。
 
143-140行,如果获取到图片,按照尺寸加载图片,否则按照尺寸加载默认图片。
 
171-181行代码是表示当屏幕划出, cannel前面的请求。
  1 public class NetworkImageView extends ImageView {
  2     /** The URL of the network image to load */
  3     private String mUrl;
  4 
  5     /**
  6      * Resource ID of the image to be used as a placeholder until the network image is loaded.
  7      */
  8     private int mDefaultImageId;
  9 
 10     /**
 11      * Resource ID of the image to be used if the network response fails.
 12      */
 13     private int mErrorImageId;
 14 
 15     /** Local copy of the ImageLoader. */
 16     private ImageLoader mImageLoader;
 17 
 18     /** Current ImageContainer. (either in-flight or finished) */
 19     private ImageContainer mImageContainer;
 20 
 21     public NetworkImageView(Context context) {
 22         this(context, null);
 23     }
 24 
 25     public NetworkImageView(Context context, AttributeSet attrs) {
 26         this(context, attrs, 0);
 27     }
 28 
 29     public NetworkImageView(Context context, AttributeSet attrs, int defStyle) {
 30         super(context, attrs, defStyle);
 31     }
 32 
 33     /**
 34      * Sets URL of the image that should be loaded into this view. Note that calling this will
 35      * immediately either set the cached image (if available) or the default image specified by
 36      * {@link NetworkImageView#setDefaultImageResId(int)} on the view.
 37      *
 38      * NOTE: If applicable, {@link NetworkImageView#setDefaultImageResId(int)} and
 39      * {@link NetworkImageView#setErrorImageResId(int)} should be called prior to calling
 40      * this function.
 41      *
 42      * @param url The URL that should be loaded into this ImageView.
 43      * @param imageLoader ImageLoader that will be used to make the request.
 44      */
 45     public void setImageUrl(String url, ImageLoader imageLoader) {
 46         mUrl = url;
 47         mImageLoader = imageLoader;
 48         // The URL has potentially changed. See if we need to load it.
 49         loadImageIfNecessary(false);
 50     }
 51 
 52     /**
 53      * Sets the default image resource ID to be used for this view until the attempt to load it
 54      * completes.
 55      */
 56     public void setDefaultImageResId(int defaultImage) {
 57         mDefaultImageId = defaultImage;
 58     }
 59 
 60     /**
 61      * Sets the error image resource ID to be used for this view in the event that the image
 62      * requested fails to load.
 63      */
 64     public void setErrorImageResId(int errorImage) {
 65         mErrorImageId = errorImage;
 66     }
 67 
 68     /**
 69      * Loads the image for the view if it isn't already loaded.
 70      * @param isInLayoutPass True if this was invoked from a layout pass, false otherwise.
 71      */
 72     void loadImageIfNecessary(final boolean isInLayoutPass) {
 73         int width = getWidth();
 74         int height = getHeight();
 75 
 76         boolean wrapWidth = false, wrapHeight = false;
 77         if (getLayoutParams() != null) {
 78             wrapWidth = getLayoutParams().width == LayoutParams.WRAP_CONTENT;
 79             wrapHeight = getLayoutParams().height == LayoutParams.WRAP_CONTENT;
 80         }
 81 
 82         // if the view's bounds aren't known yet, and this is not a wrap-content/wrap-content
 83         // view, hold off on loading the image.
 84         boolean isFullyWrapContent = wrapWidth && wrapHeight;
 85         if (width == 0 && height == 0 && !isFullyWrapContent) {
 86             return;
 87         }
 88 
 89         // if the URL to be loaded in this view is empty, cancel any old requests and clear the
 90         // currently loaded image.
 91         if (TextUtils.isEmpty(mUrl)) {
 92             if (mImageContainer != null) {
 93                 mImageContainer.cancelRequest();
 94                 mImageContainer = null;
 95             }
 96             setDefaultImageOrNull();
 97             return;
 98         }
 99 
100         // if there was an old request in this view, check if it needs to be canceled.
101         if (mImageContainer != null && mImageContainer.getRequestUrl() != null) {
102             if (mImageContainer.getRequestUrl().equals(mUrl)) {
103                 // if the request is from the same URL, return.
104                 return;
105             } else {
106                 // if there is a pre-existing request, cancel it if it's fetching a different URL.
107                 mImageContainer.cancelRequest();
108                 setDefaultImageOrNull();
109             }
110         }
111 
112         // Calculate the max image width / height to use while ignoring WRAP_CONTENT dimens.
113         int maxWidth = wrapWidth ? 0 : width;
114         int maxHeight = wrapHeight ? 0 : height;
115 
116         // The pre-existing content of this view didn't match the current URL. Load the new image
117         // from the network.
118         ImageContainer newContainer = mImageLoader.get(mUrl,
119                 new ImageListener() {
120                     @Override
121                     public void onErrorResponse(VolleyError error) {
122                         if (mErrorImageId != 0) {
123                             setImageResource(mErrorImageId);
124                         }
125                     }
126 
127                     @Override
128                     public void onResponse(final ImageContainer response, boolean isImmediate) {
129                         // If this was an immediate response that was delivered inside of a layout
130                         // pass do not set the image immediately as it will trigger a requestLayout
131                         // inside of a layout. Instead, defer setting the image by posting back to
132                         // the main thread.
133                         if (isImmediate && isInLayoutPass) {
134                             post(new Runnable() {
135                                 @Override
136                                 public void run() {
137                                     onResponse(response, false);
138                                 }
139                             });
140                             return;
141                         }
142 
143                         if (response.getBitmap() != null) {
144                             setImageBitmap(response.getBitmap());
145                         } else if (mDefaultImageId != 0) {
146                             setImageResource(mDefaultImageId);
147                         }
148                     }
149                 }, maxWidth, maxHeight);
150 
151         // update the ImageContainer to be the new bitmap container.
152         mImageContainer = newContainer;
153     }
154 
155     private void setDefaultImageOrNull() {
156         if(mDefaultImageId != 0) {
157             setImageResource(mDefaultImageId);
158         }
159         else {
160             setImageBitmap(null);
161         }
162     }
163 
164     @Override
165     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
166         super.onLayout(changed, left, top, right, bottom);
167         loadImageIfNecessary(true);
168     }
169 
170     @Override
171     protected void onDetachedFromWindow() {
172         if (mImageContainer != null) {
173             // If the view was bound to an image request, cancel it and clear
174             // out the image from the view.
175             mImageContainer.cancelRequest();
176             setImageBitmap(null);
177             // also clear out the container so we can reload the image if necessary.
178             mImageContainer = null;
179         }
180         super.onDetachedFromWindow();
181     }
182 
183     @Override
184     protected void drawableStateChanged() {
185         super.drawableStateChanged();
186         invalidate();
187     }
188 }

 

posted @ 2015-08-28 22:31  西北野狼  阅读(456)  评论(0编辑  收藏  举报