android 网络2 Volley(1)

本文示例下载地址:https://github.com/cmyeyi/NetFramework.git

1、Volley简介

Volley是一个网络通信框架,在2013年的Google I/O被推出。

Volley是一个优秀的网路访问框架,即可以通过它访问普通的网络数据,如JSON格式的数据,也可以下载图片。

2、Volley的使用场景:

Volley适合进行数据量不大但是通信频繁的网络操作,而对于数据量比较大的网络操作其表现就很糟糕了,比如使用Volley经行下载文件操作等。

3、Volley的基本用法

3.1、Volley的引入

3.1.1 Volley的下载

使用git命令下载一份Volley到本地

下载地址:https://github.com/mcxiaoke/android-volley

命令:git clone  https://github.com/mcxiaoke/android-volley

3.1.2 新建一个android工程将Volle作为一个模块引入

工程中的配置,一般在这样引入后AS会给我们自动配置

settings.gradle文件中配置如下

include ':app', ':volley'

然后在app的builde.gradle文件中配置

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support:design:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.2'
    implementation 'com.android.support:support-vector-drawable:26.1.0'
    compile project(path: ':volley')
}

在引入Volley之后可能会抱一个错误:Error:Gradle DSL method not found: 'has()'

这是因为has()方法已经不能使用了,并且从Grandle3.0中移除了,使用 hasProperty() 或 ext.has() 方法代替。

经过以上配置就可以在项目中使用Volley了

3.1.3 Volley的基本使用

3.1.3.1实践 StringRequest 
private void testStringRequest() {
    String url = "http://api.k780.com/?app=weather.history&weaid=1&date=2015-07-20&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json";
    RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
    StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            Log.i("response:", response);
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            Log.e("error",error.getMessage());
        }
    }
    );
    queue.add(stringRequest);
}

打印结果:


{
  "success": "1",
  "result": [
    {
      "weaid": "1",
      "week": "星期一",
      "cityno": "beijing",
      "citynm": "北京",
      "cityid": "101010100",
      "uptime": "2015-07-20 00:50:00",
      "temperature": "22℃",
      "humidity": "97%",
      "aqi": "101",
      "weather": "晴",
      "weather_icon": "http://api.k780.com/upload/weather/d/0.gif",
      "wind": "东北风",
      "winp": "1级",
      "temp": "22",
      "weatid": "1",
      "windid": "13",
      "winpid": "201",
      "weather_iconid": "0"
    },
    {
      "weaid": "1",
      "week": "星期一",
      "cityno": "beijing",
      "citynm": "北京",
      "cityid": "101010100",
      "uptime": "2015-07-20 01:50:00",
      "temperature": "22℃",
      "humidity": "99%",
      "aqi": "102",
      "weather": "晴",
      "weather_icon": "http://api.k780.com/upload/weather/d/0.gif",
      "wind": "东北风",
      "winp": "1级",
      "temp": "22",
      "weatid": "1",
      "windid": "13",
      "winpid": "201",
      "weather_iconid": "0"
    }
  ]
}

3.1.3.2实践 JsonRequest

在使用JsonRequest的之前我们需要先配置一下,因为我们需要将返回的json格式的数据转换成一个java实体类,所以首先我们需要根据json数据创建两个类,在浏览器上访问:

http://api.k780.com/?app=weather.history&weaid=1&date=2015-07-20&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json

从网页上将json数据复制,然后粘贴到:https://www.bejson.com/json2javapojo/这个工具中生成实体类,具体自己修改,注意可能json数据可是有问题稍微调整一下,选取下面的数据,如下图指引

生成两个类:

实体类:WeatherList

import java.util.List;

public class WeatherList {
    private String success;

    private List<Result> result;

    public void setSuccess(String success) {
        this.success = success;
    }

    public String getSuccess() {
        return this.success;
    }

    public void setResult(List<Result> result) {
        this.result = result;
    }

    public List<Result> getResult() {
        return this.result;
    }
}

实体类:Result

public class Result {
    private String weaid;

    private String week;

    private String cityno;

    private String citynm;

    private String cityid;

    private String uptime;

    private String temperature;

    private String humidity;

    private String aqi;

    private String weather;

    private String weather_icon;

    private String wind;

    private String winp;

    private String temp;

    private String weatid;

    private String windid;

    private String winpid;

    private String weather_iconid;

    public void setWeaid(String weaid) {
        this.weaid = weaid;
    }

    public String getWeaid() {
        return this.weaid;
    }

    public void setWeek(String week) {
        this.week = week;
    }

    public String getWeek() {
        return this.week;
    }

    public void setCityno(String cityno) {
        this.cityno = cityno;
    }

    public String getCityno() {
        return this.cityno;
    }

    public void setCitynm(String citynm) {
        this.citynm = citynm;
    }

    public String getCitynm() {
        return this.citynm;
    }

    public void setCityid(String cityid) {
        this.cityid = cityid;
    }

    public String getCityid() {
        return this.cityid;
    }

    public void setUptime(String uptime) {
        this.uptime = uptime;
    }

    public String getUptime() {
        return this.uptime;
    }

    public void setTemperature(String temperature) {
        this.temperature = temperature;
    }

    public String getTemperature() {
        return this.temperature;
    }

    public void setHumidity(String humidity) {
        this.humidity = humidity;
    }

    public String getHumidity() {
        return this.humidity;
    }

    public void setAqi(String aqi) {
        this.aqi = aqi;
    }

    public String getAqi() {
        return this.aqi;
    }

    public void setWeather(String weather) {
        this.weather = weather;
    }

    public String getWeather() {
        return this.weather;
    }

    public void setWeather_icon(String weather_icon) {
        this.weather_icon = weather_icon;
    }

    public String getWeather_icon() {
        return this.weather_icon;
    }

    public void setWind(String wind) {
        this.wind = wind;
    }

    public String getWind() {
        return this.wind;
    }

    public void setWinp(String winp) {
        this.winp = winp;
    }

    public String getWinp() {
        return this.winp;
    }

    public void setTemp(String temp) {
        this.temp = temp;
    }

    public String getTemp() {
        return this.temp;
    }

    public void setWeatid(String weatid) {
        this.weatid = weatid;
    }

    public String getWeatid() {
        return this.weatid;
    }

    public void setWindid(String windid) {
        this.windid = windid;
    }

    public String getWindid() {
        return this.windid;
    }

    public void setWinpid(String winpid) {
        this.winpid = winpid;
    }

    public String getWinpid() {
        return this.winpid;
    }

    public void setWeather_iconid(String weather_iconid) {
        this.weather_iconid = weather_iconid;
    }

    public String getWeather_iconid() {
        return this.weather_iconid;
    }
}

这里将要使用Gson所以还要在build.gradle中配置

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support:design:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.2'
    implementation 'com.android.support:support-vector-drawable:26.1.0'
    compile project(path: ':volley')
    compile 'com.google.code.gson:gson:2.8.5'
}

经过上面准备,就可以实践操作来了

private void testJsonRequest() {
    String url = "http://api.k780.com/?app=weather.history&weaid=1&date=2015-07-20&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json";
    RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
    JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, new Response.Listener<JSONObject>() {

        @Override
        public void onResponse(JSONObject response) {
            WeatherList weatherList = new Gson().fromJson(response.toString(), WeatherList.class);
            if(weatherList != null) {
                for(Result r : weatherList.getResult()) {
                    Log.d("##result##", "city:"+r.getCitynm() + "weather:"+ r.getWeather() +"\n");
                }
            }

        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {

        }
    });
    queue.add(jsonObjectRequest);
}

结果:
08-12 16:45:27.063 7403-7403/hq.demo.net D/##result##: city:北京weather:晴
08-12 16:45:27.063 7403-7403/hq.demo.net D/##result##: city:北京weather:晴
08-12 16:45:27.063 7403-7403/hq.demo.net D/##result##: city:北京weather:晴
08-12 16:45:27.064 7403-7403/hq.demo.net D/##result##: city:北京weather:晴
08-12 16:45:27.064 7403-7403/hq.demo.net D/##result##: city:北京weather:雷阵雨
08-12 16:45:27.064 7403-7403/hq.demo.net D/##result##: city:北京weather:雷阵雨
08-12 16:45:27.064 7403-7403/hq.demo.net D/##result##: city:北京weather:雷阵雨
08-12 16:45:27.064 7403-7403/hq.demo.net D/##result##: city:北京weather:雷阵雨
08-12 16:45:27.064 7403-7403/hq.demo.net D/##result##: city:北京weather:雷阵雨
08-12 16:45:27.064 7403-7403/hq.demo.net D/##result##: city:北京weather:雷阵雨
08-12 16:45:27.064 7403-7403/hq.demo.net D/##result##: city:北京weather:雷阵雨
08-12 16:45:27.064 7403-7403/hq.demo.net D/##result##: city:北京weather:雷阵雨
08-12 16:45:27.064 7403-7403/hq.demo.net D/##result##: city:北京weather:晴
08-12 16:45:27.064 7403-7403/hq.demo.net D/##result##: city:北京weather:雷阵雨
08-12 16:45:27.064 7403-7403/hq.demo.net D/##result##: city:北京weather:晴
08-12 16:45:27.064 7403-7403/hq.demo.net D/##result##: city:北京weather:雷阵雨
08-12 16:45:27.064 7403-7403/hq.demo.net D/##result##: city:北京weather:晴
08-12 16:45:27.064 7403-7403/hq.demo.net D/##result##: city:北京weather:晴
08-12 16:45:27.064 7403-7403/hq.demo.net D/##result##: city:北京weather:晴
08-12 16:45:27.064 7403-7403/hq.demo.net D/##result##: city:北京weather:晴
08-12 16:45:27.065 7403-7403/hq.demo.net D/##result##: city:北京weather:晴
08-12 16:45:27.065 7403-7403/hq.demo.net D/##result##: city:北京weather:晴
08-12 16:45:27.065 7403-7403/hq.demo.net D/##result##: city:北京weather:晴
08-12 16:45:27.065 7403-7403/hq.demo.net D/##result##: city:北京weather:晴

注意上面使用

JsonObjectRequest的时候要注意,它有两个构造方法,

上面使用的是

public JsonObjectRequest(String url, JSONObject jsonRequest, Listener<JSONObject> listener, ErrorListener errorListener);

如果使用

public JsonObjectRequest(int method, String url, JSONObject jsonRequest, Listener<JSONObject> listener, ErrorListener errorListener)

就要注意了,第一个参数我们可以:Request.Method.POST,如果这样那么就需要我们构造第三个参数,jsonRequest,如下

private void testJsonRequest() {
    String url = "http://api.k780.com/?app=weather.history";
    Map<String, String> params = new HashMap<String, String>();
    params.put("weaid", "1");
    params.put("date", "2015-07-20");
    params.put("appkey", "10003");
    params.put("sign", "b59bc3ef6191eb9f747dd4e83c99f2a4");
    params.put("format", "json");
    JSONObject paramJsonObject = new JSONObject(params);

    RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
    JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST,paramJsonObject, null, new Response.Listener<JSONObject>() {

        @Override
        public void onResponse(JSONObject response) {
            WeatherList weatherList = new Gson().fromJson(response.toString(), WeatherList.class);
            if(weatherList != null) {
                Log.d("##getSuccess##", "city:"+weatherList.getSuccess()+ "\n");
                for(Result r : weatherList.getResult()) {
                    Log.d("##result##", "city:"+r.getCitynm() + "weather:"+ r.getWeather() +"\n");
                }
            }

        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {

        }
    });
    queue.add(jsonObjectRequest);
}

上面使用的的post请求,但是上面是获取不到数据的,因为我们服务端是对于访问的格式不支持paramJsonObject在请求的时候再url中是一个json串,服务端不识别,这要求服务端支持。一般来说在访问之前是会登录的,会带着token过去,这样可以防止接口被攻击,所以这里记录一下。如果我们不传第一个参数,那么从源码我们可以看到,会判断第三个参数是否为null,如果为null请求方式是GET,否则是POST;

下面是源码:

/**
 * A request for retrieving a {@link JSONObject} response body at a given URL, allowing for an
 * optional {@link JSONObject} to be passed in as part of the request body.
 */
public class JsonObjectRequest extends JsonRequest<JSONObject> {

    /**
     * Creates a new request.
     * @param method the HTTP method to use
     * @param url URL to fetch the JSON from
     * @param jsonRequest A {@link JSONObject} to post with the request. Null is allowed and
     *   indicates no parameters will be posted along with request.
     * @param listener Listener to receive the JSON response
     * @param errorListener Error listener, or null to ignore errors.
     */
    public JsonObjectRequest(int method, String url, JSONObject jsonRequest,
            Listener<JSONObject> listener, ErrorListener errorListener) {
        super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener,
                    errorListener);
    }

    /**
     * Constructor which defaults to <code>GET</code> if <code>jsonRequest</code> is
     * <code>null</code>, <code>POST</code> otherwise.
     *
     * @see #JsonObjectRequest(int, String, JSONObject, Listener, ErrorListener)
     */
    public JsonObjectRequest(String url, JSONObject jsonRequest, Listener<JSONObject> listener,
            ErrorListener errorListener) {
        this(jsonRequest == null ? Method.GET : Method.POST, url, jsonRequest,
                listener, errorListener);
    }

    @Override
    protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
        try {
            String jsonString = new String(response.data,
                    HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));
            return Response.success(new JSONObject(jsonString),
                    HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        } catch (JSONException je) {
            return Response.error(new ParseError(je));
        }
    }
}

3.1.3.3实践 ImageRequest加载图片

图片的地址自己可以修改,不能保证目前使用的图片地址在被看到的时候还能够使用

private void testImageRequest() {
    String url = "http://img3.imgtn.bdimg.com/it/u=2568996661,777819818&fm=27&gp=0.jpg";

    RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
    ImageRequest jsonObjectRequest = new ImageRequest(url, new Response.Listener<Bitmap>() {

        @Override
        public void onResponse(Bitmap response) {
            if(response != null) {
                mImageView.setImageBitmap(response);
            }

        }
    }, 0, 0, ImageView.ScaleType.CENTER_CROP, Bitmap.Config.RGB_565, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {

        }
    });
    queue.add(jsonObjectRequest);
}

上面使用的方法对应接口如下,从源码中复制过来的,可以看到如果我们使用下面第二个接口,也就是不传scaleType,默认使用的缩放方式是:ScaleType.CENTER_INSIDE

/**
 * Creates a new image request, decoding to a maximum specified width and
 * height. If both width and height are zero, the image will be decoded to
 * its natural size. If one of the two is nonzero, that dimension will be
 * clamped and the other one will be set to preserve the image's aspect
 * ratio. If both width and height are nonzero, the image will be decoded to
 * be fit in the rectangle of dimensions width x height while keeping its
 * aspect ratio.
 *
 * @param url URL of the image
 * @param listener Listener to receive the decoded bitmap
 * @param maxWidth Maximum width to decode this bitmap to, or zero for none
 * @param maxHeight Maximum height to decode this bitmap to, or zero for
 *            none
 * @param scaleType The ImageViews ScaleType used to calculate the needed image size.
 * @param decodeConfig Format to decode the bitmap to
 * @param errorListener Error listener, or null to ignore errors
 */
public ImageRequest(String url, Response.Listener<Bitmap> listener, int maxWidth, int maxHeight,
        ScaleType scaleType, Config decodeConfig, Response.ErrorListener errorListener) {
    super(Method.GET, url, errorListener);
    setRetryPolicy(new DefaultRetryPolicy(DEFAULT_IMAGE_TIMEOUT_MS, DEFAULT_IMAGE_MAX_RETRIES,
            DEFAULT_IMAGE_BACKOFF_MULT));
    mListener = listener;
    mDecodeConfig = decodeConfig;
    mMaxWidth = maxWidth;
    mMaxHeight = maxHeight;
    mScaleType = scaleType;
}
/**
 * For API compatibility with the pre-ScaleType variant of the constructor. Equivalent to
 * the normal constructor with {@code ScaleType.CENTER_INSIDE}.
 */
@Deprecated
public ImageRequest(String url, Response.Listener<Bitmap> listener, int maxWidth, int maxHeight,
        Config decodeConfig, Response.ErrorListener errorListener) {
    this(url, listener, maxWidth, maxHeight,
            ScaleType.CENTER_INSIDE, decodeConfig, errorListener);
}

3.1.3.4 实践ImageLoader

实际上ImageLoader内部同样使用的是ImageRequest;

private void testImageLoader() {
    String url = "http://img3.imgtn.bdimg.com/it/u=2568996661,777819818&fm=27&gp=0.jpg";
    RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
    ImageLoader.ImageCache imageCache = new ImageLoader.ImageCache() {
        @Override
        public Bitmap getBitmap(String url) {
            return null;
        }

        @Override
        public void putBitmap(String url, Bitmap bitmap) {

        }
    };
    ImageLoader.ImageListener imageListener = ImageLoader.getImageListener(mImageView,R.mipmap.ic_launcher,R.mipmap.ic_launcher);
    ImageLoader imageLoader = new ImageLoader(queue,imageCache);
    imageLoader.get(url,imageListener);
}

ImageLoader 部分源码:

/**
 * Returns an ImageContainer for the requested URL.
 *
 * The ImageContainer will contain either the specified default bitmap or the loaded bitmap.
 * If the default was returned, the {@link ImageLoader} will be invoked when the
 * request is fulfilled.
 *
 * @param requestUrl The URL of the image to be loaded.
 */
public ImageContainer get(String requestUrl, final ImageListener listener) {
    return get(requestUrl, listener, 0, 0);
}

/**
 * Equivalent to calling {@link #get(String, ImageListener, int, int, ScaleType)} with
 * {@code Scaletype == ScaleType.CENTER_INSIDE}.
 */
public ImageContainer get(String requestUrl, ImageListener imageListener,
        int maxWidth, int maxHeight) {
    return get(requestUrl, imageListener, maxWidth, maxHeight, ScaleType.CENTER_INSIDE);
}

/**
 * Issues a bitmap request with the given URL if that image is not available
 * in the cache, and returns a bitmap container that contains all of the data
 * relating to the request (as well as the default image if the requested
 * image is not available).
 * @param requestUrl The url of the remote image
 * @param imageListener The listener to call when the remote image is loaded
 * @param maxWidth The maximum width of the returned image.
 * @param maxHeight The maximum height of the returned image.
 * @param scaleType The ImageViews ScaleType used to calculate the needed image size.
 * @return A container object that contains all of the properties of the request, as well as
 *     the currently available image (default if remote is not loaded).
 */
public ImageContainer get(String requestUrl, ImageListener imageListener,
        int maxWidth, int maxHeight, ScaleType scaleType) {

    // only fulfill requests that were initiated from the main thread.
    throwIfNotOnMainThread();

    final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight, scaleType);

    // 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<Bitmap> newRequest = makeImageRequest(requestUrl, maxWidth, maxHeight, scaleType,
            cacheKey);

    mRequestQueue.add(newRequest);
    mInFlightRequests.put(cacheKey,
            new BatchedImageRequest(newRequest, imageContainer));
    return imageContainer;
}

这里是简单使用ImageLoader来实现图片的加载,后面将单独出来讲解ImageLoader相关原理;

3.1.3.5 NetworkImageView的使用

NetworkImageView继承至ImageVIew,里面封装了ImageLoader,可以看下面的源码部分,实际上跟使用ImageLoader是一个道理


private void testNetImageView() {
    String url = "http://img3.imgtn.bdimg.com/it/u=2568996661,777819818&fm=27&gp=0.jpg";
    RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
    ImageLoader.ImageCache imageCache = new ImageLoader.ImageCache() {
        @Override
        public Bitmap getBitmap(String url) {
            return null;
        }

        @Override
        public void putBitmap(String url, Bitmap bitmap) {

        }
    };
    ImageLoader imageLoader = new ImageLoader(queue,imageCache);
    mNetworkImageView.setDefaultImageResId(R.mipmap.ic_launcher);
    mNetworkImageView.setErrorImageResId(R.mipmap.ic_launcher);
    mNetworkImageView.setImageUrl(url,imageLoader);
}

源码

/**
 * Sets URL of the image that should be loaded into this view. Note that calling this will
 * immediately either set the cached image (if available) or the default image specified by
 * {@link NetworkImageView#setDefaultImageResId(int)} on the view.
 *
 * NOTE: If applicable, {@link NetworkImageView#setDefaultImageResId(int)} and
 * {@link NetworkImageView#setErrorImageResId(int)} should be called prior to calling
 * this function.
 *
 * @param url The URL that should be loaded into this ImageView.
 * @param imageLoader ImageLoader that will be used to make the request.
 */
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);
}

/**
 * Sets the default image resource ID to be used for this view until the attempt to load it
 * completes.
 */
public void setDefaultImageResId(int defaultImage) {
    mDefaultImageId = defaultImage;
}

/**
 * Sets the error image resource ID to be used for this view in the event that the image
 * requested fails to load.
 */
public void setErrorImageResId(int errorImage) {
    mErrorImageId = 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();
    ScaleType scaleType = getScaleType();

    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, scaleType);

    // update the ImageContainer to be the new bitmap container.
    mImageContainer = newContainer;
}

项目下载地址:

https://github.com/cmyeyi/NetFramework.git

猜你喜欢

转载自blog.csdn.net/weixin_36709064/article/details/81563184