# Volley之NetWorkImageView的源码解析与用法:

来源:互联网 发布:真正的绝望是什么知乎 编辑:程序博客网 时间:2024/06/07 05:30

      • NetWorkImageView源码解析
      • NetWorkImageView具体使用
    • 总结

NetWorkImageView源码解析

/** * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.android.volley.toolbox;import android.content.Context;import android.text.TextUtils;import android.util.AttributeSet;import android.view.ViewGroup.LayoutParams;import android.widget.ImageView;import com.android.volley.VolleyError;import com.android.volley.toolbox.ImageLoader.ImageContainer;import com.android.volley.toolbox.ImageLoader.ImageListener;/** *  *从URL中获取图像以及相关请求的生命周期把控。 *这个控件在被从父控件detach的时候, 会自动取消网络请求的,即完全不用我们担心相关网络请求的生命周期问题, *而且NetworkImageView还会根据你对图片设置的width和heigh自动压缩该图片不会产生多的内存,减少OOM *还有NetworkImageView在列表中使用不会图片错位 */public class NetworkImageView extends ImageView {    /*网络加载的图片地址*/    private String mUrl;    /**     *     *在网络加载之前用作占位符的图像的资源ID,即默认图片     */    private int mDefaultImageId;    /**     *      *  如果网络响应失败,将显示失败的图像资源ID。     */    private int mErrorImageId;    /*本地Volley封装的图片加载类ImageLoader*/    private ImageLoader mImageLoader;    /*当前的图片容器,负责图片暂存和清除    private ImageContainer mImageContainer;    public NetworkImageView(Context context) {        this(context, null);    }    public NetworkImageView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public NetworkImageView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);    }    /**     *      *设置要加载到该视图中的图像ur,注意:通过ImageLoader可立即设置缓存的图像(如果有)或默认的图像指定     * @param url  加载图片的地址     * @param imageLoader  处理加载图片的类     */    public void setImageUrl(String url, ImageLoader imageLoader) {        mUrl = url;        mImageLoader = imageLoader;        // 如果网址发生改变,看看是否需要加载        loadImageIfNecessary(false);    }    /**     *   设置要用于此视图的默认图像资源ID,     */    public void setDefaultImageResId(int defaultImage) {        mDefaultImageId = defaultImage;    }    /**     *网络加载失败后显示错误图像资源ID     */    public void setErrorImageResId(int errorImage) {        mErrorImageId = errorImage;    }    /**     *   在没有赋值之前,进行图片布局尺判断(如宽、高)     * @param isInLayoutPass 如果这是一个真正的isinlayoutpass布局通过调用,否则为假。     */    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 (width == 0 && height == 0 && !isFullyWrapContent) {            return;        }        //   如果在此视图中加载的URL为空,请取消任何旧请求并清除当前加载的图像。        if (TextUtils.isEmpty(mUrl)) {            if (mImageContainer != null) {                mImageContainer.cancelRequest();                mImageContainer = null;            }            setDefaultImageOrNull();            return;        }        //    如果此视图中有旧请求,请检查是否需要取消。        if (mImageContainer != null && mImageContainer.getRequestUrl() != null) {            if (mImageContainer.getRequestUrl().equals(mUrl)) {                //   如果请求来自同一URL,返回空,亲测这里设计有些小bug。                return;            } else {                  // 如果它正在获取一个不同的URL。取消预先存在的请求,重设视图,                mImageContainer.cancelRequest();                setDefaultImageOrNull();            }        }        //   此视图的预先存在的内容与当前URL不匹配。从网络加载新的图片。        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) {                        //如果这是一个即时的反应,不设置图像立即就会引发requestLayout方法。相反,推迟返回到主线程设置图像。                        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);                        }                    }                });        // 更新imagecontainer成为新的位图容器        mImageContainer = newContainer;    }/***图片为空或者加载失败,对应情况的处理*/    private void setDefaultImageOrNull() {        if(mDefaultImageId != 0) {            setImageResource(mDefaultImageId);        }        else {            setImageBitmap(null);        }    }/***重写布局加载*/    @Override    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {        super.onLayout(changed, left, top, right, bottom);        loadImageIfNecessary(true);    }/***重写从父容器移除的方法*/    @Override    protected void onDetachedFromWindow() {        //如果图片容器不为空,从父容器清空视图        if (mImageContainer != null) {            // 从视图中取消并清除/输出图像。            mImageContainer.cancelRequest();            setImageBitmap(null);            // 如有必要, 清除容器,以便我们可以重新加载图像。            mImageContainer = null;        }        super.onDetachedFromWindow();    }/***图片发生改变(宽高的属性等),立即更新视图*/    @Override    protected void drawableStateChanged() {        super.drawableStateChanged();        invalidate();    }}

NetWorkImageView具体使用:

布局文件中的xml中使用方法

<com.android.volley.toolbox.networkimageview        android:id="@+id/image_view"        android:layout_width="100dp"        android:layout_height="100dp"        android:layout_marginTop="10dp"/>

MainActivity网络请求展示图片

public class MainActivity extends Activity {    private String path = "http://img.kaiyanapp.com/2729ed6cef6b267d456c9aacfad67b38.jpeg";    private NetworkImageView image_view;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //初始化控件image_view(NetworkImageView)findViewById(R.id.image_view);//图片加载        loadImageView(this, netWorkImageView, path);    }    /**     *      * @param mainActivity     *     */    private void loadImageView(MainActivity mainActivity, NetworkImageView iv,String url) {    //实例化imageLoader ImageLoader imageLoader = new ImageLoader(                Volley.newRequestQueue(mainActivity.getApplicationContext()), new ImageLoader.ImageCache() {                    @Override                    public Bitmap getBitmap(String s) {                        return null;                    }                    @Override                    public void putBitmap(String s, Bitmap bitmap) {                    }                });iv.setDefaultImageResId(android.R.drawable.ic_menu_camera);iv.setErrorImageResId(android.R.drawable.ic_menu_delete);iv.setImageUrl(url, imageLoader);     }}

总结

  • 丛源码解析中可以看出,volley自带的图片控件可以显示不同状态的视图。
  • 通过setImageUrl(String url, ImageLoader imageLoader)即可实现视图的展示,注意两次请求的地址一样,会返回空,不显示视图。
  • 这里没有具体对图片颜色、质量等的处理,所以倘若要封装一个考虑到这些的图片控件,还是需要做些处理。
阅读全文
0 0
原创粉丝点击