Volley源码解析及相关拓展

来源:互联网 发布:淘宝刀具店 编辑:程序博客网 时间:2024/06/05 15:58

简述

关于Volley源码解析的文章很多,这里推荐一篇CodeKK的文章——《Volley 源码解析》
—— 注:文章链接已经找不到了,但网上转载很多。

总的来说,Volley的源码比较好理解,而且具有很强的拓展性,下面贴出两张图(流程图,类图)。建议直接看源码,然后再看这两张图,分分钟就懂了。


Volley 请求流程图

这里写图片描述


Volley 框架的主要类关系图

这里写图片描述


关于Volley的拓展

根据类图,可以发现Volley支持多种类型的请求:

  • StringRequest
  • JsonRequest
    • JsonObjectRequest
    • JsonArrayRequest
  • ImageRequest
  • ClearCacheRequest

1. 自定义支持Gson解析的Request

1.1 先来看一下StringRequest

public class StringRequest extends Request<String> {    private Listener<String> mListener;    public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) {        super(method, url, errorListener);        mListener = listener;    }    public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {        this(Method.GET, url, listener, errorListener);    }    @Override    protected void deliverResponse(String response) {        if (mListener != null) {            mListener.onResponse(response);        }    }    @Override    protected Response<String> parseNetworkResponse(NetworkResponse response) {        String parsed;        try {            // 主要是这里将网络获取的数据转成String类型            parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));        } catch (UnsupportedEncodingException e) {            parsed = new String(response.data);        }        // 这里只是将String类型的数据存放在Response对象的一个result字段里        return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));    }}

1.2 支持Gson解析的Request

前提:数据的返回类型必须是json格式的。

public class GsonRequest extends Request<T> {    private Listener<T> mListener;    private final Class<T> clazz;    private final Gson gson = new Gson();    // 这里要传一个实体对象进去    public StringRequest(String url, Class<T> clazz, Listener<String> listener, ErrorListener errorListener) {        super(Method.GET, url, listener, errorListener);        mListener = listener;        this.clazz = clazz;     }    @Override    protected void deliverResponse(T response) {        if (mListener != null) {            mListener.onResponse(response);        }    }    @Override      protected Response<T> parseNetworkResponse(NetworkResponse response) {          try {            // 先转成String类型的json            String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers));              // 解析String (关键)            return Response.success(gson.fromJson(json, clazz), HttpHeaderParser.parseCacheHeaders(response));          } catch (UnsupportedEncodingException e) {              return Response.error(new ParseError(e));          } catch (JsonSyntaxException e) {              return Response.error(new ParseError(e));          }      }  }

2. ImageRequest中图片处理的学习

public class ImageRequest extends Request<Bitmap> {    /** Socket timeout in milliseconds for image requests */    private static final int IMAGE_TIMEOUT_MS = 1000;    /** Default number of retries for image requests */    private static final int IMAGE_MAX_RETRIES = 2;    /** Default backoff multiplier for image requests */    private static final float IMAGE_BACKOFF_MULT = 2f;    private final Response.Listener<Bitmap> mListener;    private final Config mDecodeConfig;    private final int mMaxWidth;    private final int mMaxHeight;    private ScaleType mScaleType;    /** Decoding lock so that we don't decode more than one image at a time (to avoid OOM's) */    private static final Object sDecodeLock = new Object();    /**     * Creates a new image request.     */    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(IMAGE_TIMEOUT_MS, IMAGE_MAX_RETRIES, IMAGE_BACKOFF_MULT));        mListener = listener;        mDecodeConfig = decodeConfig;        mMaxWidth = maxWidth;        mMaxHeight = maxHeight;        mScaleType = scaleType;    }    /**     * Scales one side of a rectangle to fit aspect ratio.     */    private static int getResizedDimension(int maxPrimary, int maxSecondary, int actualPrimary, int actualSecondary, ScaleType scaleType) {        // If no dominant value at all, just return the actual.        if ((maxPrimary == 0) && (maxSecondary == 0)) {            return actualPrimary;        }        // If ScaleType.FIT_XY fill the whole rectangle, ignore ratio.        if (scaleType == ScaleType.FIT_XY) {            if (maxPrimary == 0) {                return actualPrimary;            }            return maxPrimary;        }        // If primary is unspecified, scale primary to match secondary's scaling ratio.        if (maxPrimary == 0) {            double ratio = (double) maxSecondary / (double) actualSecondary;            return (int) (actualPrimary * ratio);        }        if (maxSecondary == 0) {            return maxPrimary;        }        double ratio = (double) actualSecondary / (double) actualPrimary;        int resized = maxPrimary;        // If ScaleType.CENTER_CROP fill the whole rectangle, preserve aspect ratio.        if (scaleType == ScaleType.CENTER_CROP) {            if ((resized * ratio) < maxSecondary) {                resized = (int) (maxSecondary / ratio);            }            return resized;        }        if ((resized * ratio) > maxSecondary) {            resized = (int) (maxSecondary / ratio);        }        return resized;    }    @Override    protected Response<Bitmap> parseNetworkResponse(NetworkResponse response) {        // Serialize all decode on a global lock to reduce concurrent heap usage.        synchronized (sDecodeLock) {            try {                return doParse(response);            } catch (OutOfMemoryError e) {                VolleyLog.e("Caught OOM for %d byte image, url=%s", response.data.length, getUrl());                return Response.error(new ParseError(e));            }        }    }    /**     * 图片的主要处理逻辑(值得参考)     * 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, mScaleType);            int desiredHeight = getResizedDimension(mMaxHeight, mMaxWidth,                    actualHeight, actualWidth, mScaleType);            // 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));        }    }    @Override    protected void deliverResponse(Bitmap response) {        mListener.onResponse(response);    }    /**     * 返回一个inSimpleSize的最佳值     */    static int findBestSampleSize(            int actualWidth, int actualHeight, int desiredWidth, int desiredHeight) {        double wr = (double) actualWidth / desiredWidth;        double hr = (double) actualHeight / desiredHeight;        double ratio = Math.min(wr, hr);        float n = 1.0f;        while ((n * 2) <= ratio) {            n *= 2;        }        return (int) n;    }}

0 0
原创粉丝点击