volley源码分析

来源:互联网 发布:设置网络位置选哪个好 编辑:程序博客网 时间:2024/06/12 20:11

volley源码分析

背景:在2013年Google I/O大会上推出了一个新的网络通信框架Volley。Volley既可以访问网络取得数据,也可以加载图片,并且在性能方面也进行了大幅度的调整,它的设计目标就是非常适合去进行数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕
ok~ 废话不多说直接进入正题;首先简单介绍volley的简单代码实现<以StringRequest为例>:

RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());StringRequest mStringRequest = new StringRequest(Request.Method.GET, "http://www.baidu.com",        new Response.Listener<String>() {            @Override            public void onResponse(String response) {                Log.i("wangshu", response);            }        }, new Response.ErrorListener() {    @Override    public void onErrorResponse(VolleyError error) {        Log.e("wangshu", error.getMessage(), error);    }});//将请求添加在请求队列中mQueue.add(mStringRequest);

1.Volley.newRequestQueue(getApplicationContext());

当然不一定使用StringRequest,也可以特殊指定其他,这里不多说详见volley的详细使用;接着看源码;首先是请求队列的创建:

 public static RequestQueue newRequestQueue(Context context) {        return newRequestQueue(context, (HttpStack)null);    }public static RequestQueue newRequestQueue(Context context, HttpStack stack) {        return newRequestQueue(context, stack, -1);    }

可见request实例化最终调用return newRequestQueue(context, stack, -1);so~ 接着看其源码:

public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {        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 var7) {            ;        }        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;        if(maxDiskCacheBytes <= -1) {            queue1 = new RequestQueue(new DiskBasedCache(cacheDir), network1);        } else {            queue1 = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network1);        }        queue1.start();        return queue1;    }

可以看到newRequestQueue中网络请求的主题是基于httpConnection的HurlStack2.3>和基于httpClient的HttpClientStack;最终创建queue<即请求队列>,然后走queue1.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();      }  }

可以看到strat方法中初始化缓冲调度线程CacheDispatcher和遍历网络调度线程networkDispatcher,一般为4个,最后通过start()方法全部开启;

2.mQueue.add(mStringRequest);

接着为了方便理解,先看:

//将请求添加在请求队列中mQueue.add(mStringRequest);

下面看add这个方法的源码:

public <T> Request<T> add(Request<T> request) {       request.setRequestQueue(this);       Set var2 = this.mCurrentRequests;       synchronized(this.mCurrentRequests) {           this.mCurrentRequests.add(request);       }       request.setSequence(this.getSequenceNumber());       request.addMarker("add-to-queue");       //如果不能缓存,则将请求添加到网络请求队列中       if(!request.shouldCache()) {           this.mNetworkQueue.add(request);           return request;       } else {           Map var8 = this.mWaitingRequests;           synchronized(this.mWaitingRequests) {               String cacheKey = request.getCacheKey();//之前是否有执行相同的请求且还没有返回结果的,如果有的话将此请求加入mWaitingRequests队列,不再重复请求               if(this.mWaitingRequests.containsKey(cacheKey)) {                   Object stagedRequests = (Queue)this.mWaitingRequests.get(cacheKey);                   if(stagedRequests == null) {                       stagedRequests = new LinkedList();                   }                   ((Queue)stagedRequests).add(request);                   this.mWaitingRequests.put(cacheKey, stagedRequests);                   if(VolleyLog.DEBUG) {                       VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", new Object[]{cacheKey});                   }               } else {  //没有的话就将请求加入缓存队列mCacheQueue,同时加入mWaitingRequests中用来做下次同样请求来时的重复判断依据                   this.mWaitingRequests.put(cacheKey, (Object)null);                   this.mCacheQueue.add(request);               }               return request;           }       }   }

通过判断request.shouldCache(),来判断是否可以缓存,默认是可以缓存的,如果不能缓存,则将请求添加到网络请求队列中,如果能缓存就判断之前是否有执行相同的请求且还没有返回结果的,如果有的话将此请求加入mWaitingRequests队列,不再重复请求;没有的话就将请求加入缓存队列mCacheQueue,同时加入mWaitingRequests中用来做下次同样请求来时的重复判断依据。
当将请求添加到网络请求队列或者缓存队列时,这时在后台的网络调度线程和缓存调度线程轮询各自的请求队列发现有请求任务则开始执行,我们先看看缓存调度线程。

3.CacheDispatcher缓存调度线程

    先看其中重写的run():
public void run() {    if(DEBUG) {        VolleyLog.v("start new dispatcher", new Object[0]);    }    //线程优先级设置为最高级别    Process.setThreadPriority(10);    this.mCache.initialize();    while(true) {        while(true) {            while(true) {                while(true) {                    try {                    //获取缓存队列中的一个请求                        final Request e = (Request)this.mCacheQueue.take();                        e.addMarker("cache-queue-take");                        //如果请求取消了则将请求停止掉                        if(e.isCanceled()) {                            e.finish("cache-discard-canceled");                        } else {                        //查看是否有缓存的响应                            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");                                //对数据进行解析并回调给主线程                                Response response = e.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));                                e.addMarker("cache-hit-parsed");                                if(!entry.refreshNeeded()) {                                    this.mDelivery.postResponse(e, response);                                } else {                                    e.addMarker("cache-hit-refresh-needed");                                    e.setCacheEntry(entry);                                    response.intermediate = true;                                    this.mDelivery.postResponse(e, response, new Runnable() {                                        public void run() {                                            try {                                                CacheDispatcher.this.mNetworkQueue.put(e);                                            } catch (InterruptedException var2) {                                                ;                                            }                                        }                                    });                                }                            } else {                                e.addMarker("cache-hit-expired");                                e.setCacheEntry(entry);                                this.mNetworkQueue.put(e);                            }                        }                    } catch (InterruptedException var4) {                        if(this.mQuit) {                            return;                        }                    }                }            }        }    }}static {    DEBUG = VolleyLog.DEBUG;}

上面代码有多重判断:是否取消请求—->没有取消,判断是否有缓存—–>有缓冲,判断是否过期—–>没有过期,则回调主线程;接着看网络调度;

4.NetworkDispatcher网络调度线程

同样来看其run方法:

public void run() {       Process.setThreadPriority(10);       while(true) {           long startTimeMs;           Request request;           while(true) {               startTimeMs = SystemClock.elapsedRealtime();               try {               //从队列中取出请求                   request = (Request)this.mQueue.take();                   break;               } catch (InterruptedException var6) {                   if(this.mQuit) {                       return;                   }               }           }           try {               request.addMarker("network-queue-take");               if(request.isCanceled()) {                   request.finish("network-discard-cancelled");               } else {                   this.addTrafficStatsTag(request);                   //请求网络                   NetworkResponse e = this.mNetwork.performRequest(request);                   request.addMarker("network-http-complete");                   if(e.notModified && request.hasHadResponseDelivered()) {                       request.finish("not-modified");                   } else {                       Response volleyError1 = request.parseNetworkResponse(e);                       request.addMarker("network-parse-complete");                       if(request.shouldCache() && volleyError1.cacheEntry != null) {                                                    //将响应结果存入缓存                           this.mCache.put(request.getCacheKey(), volleyError1.cacheEntry);                           request.addMarker("network-cache-written");                       }                       request.markDelivered();                       this.mDelivery.postResponse(request, volleyError1);                   }               }           } catch (VolleyError var7) {               var7.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);               this.parseAndDeliverNetworkError(request, var7);           } catch (Exception var8) {               VolleyLog.e(var8, "Unhandled exception %s", new Object[]{var8.toString()});               VolleyError volleyError = new VolleyError(var8);               volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);               this.mDelivery.postError(request, volleyError);           }       }   }

可以看到当请求正常传达时候会有网络请求:

//请求网络                   NetworkResponse e = this.mNetwork.performRequest(request);

请求网络时调用this.mNetwork.performRequest(request),这个mNetwork是一个接口,实现它的类是BasicNetwork,我们来看看BasicNetwork的performRequest()方法:

public NetworkResponse performRequest(Request<?> request) throws VolleyError {    long requestStart = SystemClock.elapsedRealtime();        while(true) {            HttpResponse httpResponse = null;            Object responseContents = null;            Map responseHeaders = Collections.emptyMap();            try {                HashMap e = new HashMap();                this.addCacheHeaders(e, request.getCacheEntry());                httpResponse = this.mHttpStack.performRequest(request, e);                StatusLine statusCode1 = httpResponse.getStatusLine();                int networkResponse1 = statusCode1.getStatusCode();                responseHeaders = convertHeaders(httpResponse.getAllHeaders());                if(networkResponse1 == 304) {                    Entry requestLifetime2 = request.getCacheEntry();                    if(requestLifetime2 == null) {                        return new NetworkResponse(304, (byte[])null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);                    }                    requestLifetime2.responseHeaders.putAll(responseHeaders);                    return new NetworkResponse(304, requestLifetime2.data, requestLifetime2.responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);                }

this.mHttpStack.performRequest(request, e);从这段代码 开始请求网络,然后根据不同的响应码返回不同的NetworkResponse,回看NetworkDispatcher,当请求之后响应结果成功会调用this.mDelivery.postResponse(request, volleyError1);

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

然后继续看ResponseDeliveryRunnable:

private class ResponseDeliveryRunnable implements Runnable {       private final Request mRequest;       private final Response mResponse;       private final Runnable mRunnable;       public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) {           this.mRequest = request;           this.mResponse = response;           this.mRunnable = runnable;       }       public void run() {           if(this.mRequest.isCanceled()) {               this.mRequest.finish("canceled-at-delivery");           } else {               if(this.mResponse.isSuccess()) {                   this.mRequest.deliverResponse(this.mResponse.result);               } else {                   this.mRequest.deliverError(this.mResponse.error);               }               if(this.mResponse.intermediate) {                   this.mRequest.addMarker("intermediate-response");               } else {                   this.mRequest.finish("done");               }               if(this.mRunnable != null) {                   this.mRunnable.run();               }           }       }   }

上述代码中关键性代码:

this.mRequest.deliverResponse(this.mResponse.result); this.mRequest.deliverError(this.mResponse.error);

接着看StringRequest源码:

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 void deliverError(String error) {        this.mListener.onErrorResponse(error);    }}

在deliverResponse方法中调用了this.mListener.onResponse(response),最终将response回调给了Response.Listener的onResponse()方法。我们用StringRequest请求网络的写法是这样的:

RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());        StringRequest mStringRequest = new StringRequest(Request.Method.GET, "http://www.baidu.com",                new Response.Listener<String>() {                    @Override                    public void onResponse(String response) {                        Log.i("wangshu", response);                    }                }, new Response.ErrorListener() {            @Override            public void onErrorResponse(VolleyError error) {                Log.e("wangshu", error.getMessage(), error);            }        });        //将请求添加在请求队列中        mQueue.add(mStringRequest);

个人感觉volley的逻辑微微有些乱,如果理解不是很顺畅,建议一边看博文 一边画图理解一下.谢谢 支持

原创粉丝点击