Android:Volley源码解析

来源:互联网 发布:怎么联系淘宝直播达人 编辑:程序博客网 时间:2024/06/06 01:05

简单实例

Volley是一个封装HttpUrlConnection和HttpClient的网络通信框架,集AsyncHttpClient和Universal-Image-Loader的优点于了一身,既可以像AsyncHttpClient一样非常简单地进行HTTP通信,也可以像Universal-Image-Loader一样轻松加载并缓存下载的图片。Volley在性能方面也进行了大幅度的调整,它的设计目标就是进行数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会比较糟糕。从下面这个简单的实例来研究一下源码。

RequestQueue mQueue = Volley.newRequestQueue(MainActivity.this);StringRequest stringRequest = new StringRequest("http://www.baidu.com", new Response.Listener<String>() {    @Override    public void onResponse(String s) {        tv.setText(s);    }}, new Response.ErrorListener() {    @Override    public void onErrorResponse(VolleyError volleyError) {    }});mQueue.add(stringRequest);

流程

1、以静态工厂形式实例化一个RequestQueue对象

RequestQueue mQueue = Volley.newRequestQueue(MainActivity.this);

  • 首先看一下RequestQueue这个类:
public class RequestQueue {    private AtomicInteger mSequenceGenerator;    private final Map<String, Queue<Request>> mWaitingRequests;    private final Set<Request> mCurrentRequests;    private final PriorityBlockingQueue<Request> mCacheQueue;    private final PriorityBlockingQueue<Request> mNetworkQueue;    private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;    private final Cache mCache;    private final Network mNetwork;    private final ResponseDelivery mDelivery;    private NetworkDispatcher[] mDispatchers;    private CacheDispatcher mCacheDispatcher;    public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) {        this.mSequenceGenerator = new AtomicInteger();        this.mWaitingRequests = new HashMap();        this.mCurrentRequests = new HashSet();        this.mCacheQueue = new PriorityBlockingQueue();        this.mNetworkQueue = new PriorityBlockingQueue();        this.mCache = cache;        this.mNetwork = network;        this.mDispatchers = new NetworkDispatcher[threadPoolSize];        this.mDelivery = delivery;    }    public RequestQueue(Cache cache, Network network, int threadPoolSize) {        this(cache, network, threadPoolSize, new ExecutorDelivery(new Handler(Looper.getMainLooper())));    }    public RequestQueue(Cache cache, Network network) {        this(cache, network, 4);    }    ...}

从构造函数可知,mWaitingRequests、mCurrentRequests、mCacheQueue、mNetworkQueue是以组合形式实例化,后两者是阻塞队列;而mCache、mNetwork是以聚合形式注入;mDelivery默认也是组合形式new ExecutorDelivery(new Handler(Looper.getMainLooper())))实例化。

  • newRequestQueue方法:
public static RequestQueue newRequestQueue(Context context) {        return newRequestQueue(context, (HttpStack)null);    }
 public static RequestQueue newRequestQueue(Context context, HttpStack stack) {        File cacheDir = new File(context.getCacheDir(), "volley");        String userAgent = "volley/0";        try {            String network = context.getPackageName();            PackageInfo queue = context.getPackageManager().getPackageInfo(network, 0);            userAgent = network + "/" + queue.versionCode;        } catch (NameNotFoundException var6) {            ;        }        if(stack == null) {            if(VERSION.SDK_INT >= 9) {                stack = new HurlStack();            } else {                stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));            }        }        BasicNetwork network1 = new BasicNetwork((HttpStack)stack);        RequestQueue queue1 = new RequestQueue(new DiskBasedCache(cacheDir), network1);        queue1.start();        return queue1;    }

结合RequestQueue类可知,实例化的RequestQueue对象,注入了new DiskBasedCache(cacheDir)network1,缓存方式默认是磁盘缓存,NetWork对象会根据系统版本,选用不同的Http通信方式。

  • queue.start()方法
public void start() {        this.stop();        this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery);        this.mCacheDispatcher.start();        for(int i = 0; i < this.mDispatchers.length; ++i) {            NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery);            this.mDispatchers[i] = networkDispatcher;            networkDispatcher.start();        }    }

CacheDispatcher和NetworkDispatcher都是继承Thread类,所以这个方法生成一条缓存分发线程,和四条网络线程。

  • CacheDispatcher类继承Thread类,所有参数都是聚合形式注入,看下关键的run()方法,由于代码较长,这里不贴了,分段分析下几个比较重要的方法
while(true){    ...    Request e = (Request)this.mCacheQueue.take();    ...}

首先任务是一个死循环,由于mCacheQueue是个阻塞队列,所以将不断地从阻塞队列读取Request


 Entry entry = this.mCache.get(e.getCacheKey());                                    if(entry == null) {                                        e.addMarker("cache-miss");                                        this.mNetworkQueue.put(e);                                    } else if(entry.isExpired()) {                                        e.addMarker("cache-hit-expired");                                        e.setCacheEntry(entry);                                        this.mNetworkQueue.put(e);                                    } else {                                        e.addMarker("cache-hit");                                        Response response = e.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));                                        ...                                        }

判断请求是否有缓存,如果没有或者缓存已经过期,将请求放到网络队列里面。否则找到缓存,则进行下面的操作。


Response response = e.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));

parseNetworkResponse是Request类的抽象方法,我们进去StringRequest看下:

protected Response<String> parseNetworkResponse(NetworkResponse response) {        String parsed;        try {            parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));        } catch (UnsupportedEncodingException var4) {            parsed = new String(response.data);        }        return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));    }

可看作是对网络下载的数据进行解析处理,然后返回。


this.mDelivery.postResponse(e, response);

最后进行这一步,mDelivery是在RequestQueue里面实例化后注入CacheDispatcher的,具体的实例化对象:new ExecutorDelivery(new Handler(Looper.getMainLooper()))。看下ExecutorDelivery类,找到postResponse方法。

    public void postResponse(Request<?> request, Response<?> response) {        this.postResponse(request, response, (Runnable)null);    }    public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {    ...        this.mResponsePoster.execute(new ExecutorDelivery.ResponseDeliveryRunnable(request, response, runnable));    }

继续往下看

private class ResponseDeliveryRunnable implements Runnable {    ...    run(){        ...        if(this.mResponse.isSuccess()) {                    this.mRequest.deliverResponse(this.mResponse.result);                }         ...    }    ...}

deliverResponse方法同样是Request类的抽象方法,我们进去StringRequest看下

    protected void deliverResponse(String response) {        this.mListener.onResponse(response);    }

就一句回调


  • NetworkDispatcher类同样继承Thread类,其分析过程和CacheDispatcher差不多,重要的同样是以下几步:

1、从网络阻塞队列读取请求,request = (Request)this.mQueue.take();
2、网络下载,NetworkResponse e = this.mNetwork.performRequest(request);(如果是CacheDispatcher这一步就是缓存判断)
3、处理下载后的数据,Response response = request.parseNetworkResponse(e);
3、对处理后的数据进行回调,this.mDelivery.postResponse(e, response)。


2、实例化一个Request对象

StringRequest stringRequest = new StringRequest (url,listener,errorListener);

public class StringRequest extends Request<String> {    private final Listener<String> mListener;    public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) {        super(method, url, errorListener);        this.mListener = listener;    }    public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {        this(0, url, listener, errorListener);    }    protected void deliverResponse(String response) {        this.mListener.onResponse(response);    }    protected Response<String> parseNetworkResponse(NetworkResponse response) {        String parsed;        try {            parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));        } catch (UnsupportedEncodingException var4) {            parsed = new String(response.data);        }        return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));    }}

由第一个分析步骤可以知道,这个Request主要就是进行两个操作,也就是重写两个方法。

  1. protected abstract Response<T> parseNetworkResponse(NetworkResponse var1);对下载后的数据进行解析处理;
  2. protected abstract void deliverResponse(T var1);最后回调操作这个数据的方法。

所以构造函数仅需下载地址和回调操作的方法。


3、调用queue.add()方法

 if(!request.shouldCache()) {            this.mNetworkQueue.add(request);            return request;        } 

如果不需要缓存就直接添加到网络队列里面,Request有个比较重要的布尔字段mShouldCache,默认是用来判断是否要进行磁盘缓存的。


this.mCacheQueue.add(request);

否则将其添加到缓存队列,这个方法上面也会进行一些当前队列和等待队列的防重复的操作。


小结

这里写图片描述

框架部分:
1、实例化一个RequestQueue对象,开启一条缓存线程和默认的四条网络线程,线程不断地从缓存阻塞队列和网络阻塞队列里面读取请求;
2、如果缓存线程从缓存队列里面读取的请求已经缓存过,则解析数据回调操作方法,否则将其添加到网络队列;
3、如果缓存线程从缓存队列里面读取的请求没有缓存过,则添加到网络队列。
4、网络线程从网络阻塞队列不断读取请求,读到请求后则由封装好的HttpStack对象进行网络下载处理、下载后回调对数据处理的方法,处理后回调操作数据的方法。

客户部分:
1、实例化一个请求对象,在请求对象里面重写处理网络下载后的数据的方法,和操作处理后的数据的方法。
2、将请求对象添加到请求队列,请求需要缓存则会被添加到分配到缓存队列,不需要则被添加到网络队列。


之前看过一个问题,说框架和库有什么不同,高人答曰:框架是他调用你代码,库是你调用他代码。优秀的框架拓展性是如此之强,虽然自己远没那个能力,不过也算开了眼界!

0 0