[Android]Volley源码分析(五)

前面几篇通过源码分析了Volley是怎样进行请求调度及请求是如何被实际执行的,这篇最后来看下请求结果是如何交付给请求者的(一般是Android的UI主线程)。

类图:

请求结果的交付是通过ResponseDelivery接口完成的,它有一个实现类ExecutorDelivery, 主要有postResponse()与postError()两个方法,分别在请求成功或失败时将结果提交给请求发起者。

1. 首先,在NetworkDispatcher的run()方法中,当服务器返回响应并解析完后,会调用mDelivery.postResponse(request, response);来提交请求响应。

 1  @Override
 2     public void run() {
 3         Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
 4         Request<?> request;
 5         while (true) {
 6             try {
 7                 // Take a request from the queue.
 8                 request = mQueue.take();
 9             } catch (InterruptedException e) {
10                 // We may have been interrupted because it was time to quit.
11                 if (mQuit) {
12                     return;
13                 }
14                 continue;
15             }
16
17             try {
18                 request.addMarker("network-queue-take");
19
20                 // If the request was cancelled already, do not perform the
21                 // network request.
22                 if (request.isCanceled()) {
23                     request.finish("network-discard-cancelled");
24                     continue;
25                 }
26
27                 addTrafficStatsTag(request);
28
29                 // Perform the network request.
30                 NetworkResponse networkResponse = mNetwork.performRequest(request);
31                 request.addMarker("network-http-complete");
32
33                 // If the server returned 304 AND we delivered a response already,
34                 // we‘re done -- don‘t deliver a second identical response.
35                 if (networkResponse.notModified && request.hasHadResponseDelivered()) {
36                     request.finish("not-modified");
37                     continue;
38                 }
39
40                 // Parse the response here on the worker thread.
41                 Response<?> response = request.parseNetworkResponse(networkResponse);
42                 request.addMarker("network-parse-complete");
43
44                 // Write to cache if applicable.
45                 // TODO: Only update cache metadata instead of entire record for 304s.
46                 if (request.shouldCache() && response.cacheEntry != null) {
47                     mCache.put(request.getCacheKey(), response.cacheEntry);
48                     request.addMarker("network-cache-written");
49                 }
50
51                 // Post the response back.
52                 request.markDelivered();
53                 mDelivery.postResponse(request, response);
54             } catch (VolleyError volleyError) {
55                 parseAndDeliverNetworkError(request, volleyError);
56             } catch (Exception e) {
57                 VolleyLog.e(e, "Unhandled exception %s", e.toString());
58                 mDelivery.postError(request, new VolleyError(e));
59             }
60         }
61     }

2. 看ExecutorDelivery中postResponse()方法的具体实现。其中mResponsePoster是一个Executor。每post一个response,都会调用ResponseDeliveryRunnable的run()方法。在这个run()方法中,会通过mRequest.deliverResponse(mResponse.result)来传递response的result,这个result其实就是已经解析好的响应结果,比如一个表示处理结果的字符串或一个User对象。

 1 @Override
 2     public void postResponse(Request<?> request, Response<?> response) {
 3         postResponse(request, response, null);
 4     }
 5
 6     @Override
 7     public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
 8         request.markDelivered();
 9         request.addMarker("post-response");
10         mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
11     }
12
13 /**
14      * A Runnable used for delivering network responses to a listener on the
15      * main thread.
16      */
17     @SuppressWarnings("rawtypes")
18     private class ResponseDeliveryRunnable implements Runnable {
19         private final Request mRequest;
20         private final Response mResponse;
21         private final Runnable mRunnable;
22
23         public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) {
24             mRequest = request;
25             mResponse = response;
26             mRunnable = runnable;
27         }
28
29         @SuppressWarnings("unchecked")
30         @Override
31         public void run() {
32             // If this request has canceled, finish it and don‘t deliver.
33             if (mRequest.isCanceled()) {
34                 mRequest.finish("canceled-at-delivery");
35                 return;
36             }
37
38             // Deliver a normal response or error, depending.
39             if (mResponse.isSuccess()) {
40                 mRequest.deliverResponse(mResponse.result);
41             } else {
42                 mRequest.deliverError(mResponse.error);
43             }
44
45             // If this is an intermediate response, add a marker, otherwise we‘re done
46             // and the request can be finished.
47             if (mResponse.intermediate) {
48                 mRequest.addMarker("intermediate-response");
49             } else {
50                 mRequest.finish("done");
51             }
52
53             // If we have been provided a post-delivery runnable, run it.
54             if (mRunnable != null) {
55                 mRunnable.run();
56             }
57        }
58     }

3. 既然是通过Request的deliverResponse()来传递响应结果,就来看下这个方法, 第二篇中已经知道这个方法是个抽象函数,由它子类来实现。以第一篇中的MyGsonRequest为例,其实现很简单,就是调用了mListener的onResponse方法。

1 @Override
2     protected void deliverResponse(T response) {
3         mListener.onResponse(response);
4     }

这个mListener就是在主线程实例化MyGsonRequest的时候,传过来的一个Response.Listener<T>实例,这是MyGsonRequest的构造函数:

 1 public MyGsonRequest(int method
 2                         , String url
 3                         , Object requestBody
 4                         , Class<T> responseClass
 5                         , Listener<T> listener
 6                         , ErrorListener errorListener) {
 7
 8         super(method, url, errorListener);
 9         this.mRequestBody = requestBody;
10         this.mResponseClass = responseClass;
11         this.mListener = listener;
12         mGson = new Gson();
13
14     }

这里mListener也就是第一篇中在主线程中通过createRegisterSuccessListener函数返回的监听器实例,如下代码所示。  所以最终会调到这里的onResponse()方法,来做一些更新UI或提示用户请求成功之类的操作。请求失败时,响应错误结果的提交与之类似。这样,Volley就完成了响应结果的交付。

 1 private Listener<String> createRegisterSuccessListener() {
 2         return new Listener<String>() {
 3             @Override
 4             public void onResponse(String response) {
 5                 if (mProgressDialog != null) {
 6                     mProgressDialog.dismiss();
 7                 }
 8                 Toast.makeText(
 9                         RegisterActivity.this,
10                         getString(R.string.msg_register_success),
11                         Toast.LENGTH_SHORT).show();
12
13             }
14         };
15     }

这里还有一个问题, 因为更新UI的操作只能在主线程中进行,那么ResponseDeliveryRunnable的run()方法不能再新起一个线程来执行,而应该在主线程中执行,这个是如何做到的?

其实还是用的Handler,Looper,MessageQueue的那套机制。 在Volley初始化一个RequestQueue的时候,会调用RequestQueue的如下构造函数,它构建了一个ExecutorDelivery对象,并把一个与主线程的Looper关联的一个Handler,

1 public RequestQueue(Cache cache, Network network, int threadPoolSize) {
2         this(cache, network, threadPoolSize,
3                 new ExecutorDelivery(new Handler(Looper.getMainLooper())));
4     }

然后再看下ExecutorDelivery的构造方法, 通过handler的post方法,把ResponseDeliveryRunnable 这个runnable加到了主线程的消息队列中,所以它的run()方法是在主线程中执行的。

1     public ExecutorDelivery(final Handler handler) {
2         // Make an Executor that just wraps the handler.
3         mResponsePoster = new Executor() {
4             @Override
5             public void execute(Runnable command) {
6                 handler.post(command);
7             }
8         };
9     }

到这里,Volley的源码基本上看完了。 还有一些诸如NetworkImageView控件(这个挺好用,直接可以取代ImageView),以及Cache的一些实现,有时间再具体看看。

[Android]Volley源码分析(五)

时间: 2024-11-08 22:28:35

[Android]Volley源码分析(五)的相关文章

[Android] Volley源码分析(五)答疑

Volley源码分析系列出了有一段日子了,有不少看官私底下给我留言,同时抛出了一些问题.对于一些比较简单的问题我们跳过去,这两天接到网友是@smali提出的问题.不得不赞一下这位看官看源码时候的细腻程度,我引出这个问题供大家一块思考一下. Q:在写入文件头数据的时候为何不直接写入Int而是通过移位的方式来完成? 我们来看一下对应的源码: writeInt(os, CACHE_MAGIC); static void writeInt(OutputStream os, int n) throws I

[Android]Volley源码分析(四)

上篇中有提到NetworkDispatcher是通过mNetwork(Network类型)来进行网络访问的,现在来看一下关于Network是如何进行网络访问的. Network部分的类图: Network有一个实现类BasicNetwork,它有一个mHttpStack的属性,实际的网络请求是由这个mHttpStack来进行的,看BasicNetwork的performRequest()方法, 1 @Override 2 public NetworkResponse performRequest

[Android]Volley源码分析(二)Cache

Cache作为Volley最为核心的一部分,Volley花了重彩来实现它.本章我们顺着Volley的源码思路往下,来看下Volley对Cache的处理逻辑. 我们回想一下昨天的简单代码,我们的入口是从构造一个Request队列开始的,而我们并不直接调用new来构造,而是将控制权反转给Volley这个静态工厂来构造. com.android.volley.toolbox.Volley: public static RequestQueue newRequestQueue(Context conte

[Android]Volley源码分析(叁)Network

如果各位看官仔细看过我之前的文章,实际上Network这块的只是点小功能的补充.我们来看下NetworkDispatcher的核心处理逻辑: <span style="font-size:18px;">while (true) { try { // Take a request from the queue. request = mQueue.take(); } catch (InterruptedException e) { // We may have been int

[Android]Volley源码分析(肆)应用

通过前面的讲述,相信你已经对Volley的原理有了一定了解.本章将举一些我们能在应用中直接用到的例子,第一个例子是 NetworkImageView类,其实NetworkImageView顾名思义就是将异步的操作封装在了控件本身,这种设计可以充分保留控件的移植性和维护性.NetworkImageView通过调用setImageUrl来指定具体的url: public void setImageUrl(String url, ImageLoader imageLoader) { mUrl = ur

[Android] Volley源码分析(一)体系结构

Volley:google出的一个用于异步处理的框架.由于本身的易用性和良好的api,使得它能得以广泛的应用.我还是一如既往从源码的方向上来把控它.我们先通过一段简单的代码来了解Volley RequestQueue queue = Volley.newRequestQueue(this); ImageRequest imagerequest = new ImageRequest(url, new Response.Listener<Bitmap>(){ @Override public vo

[Android]Volley源码分析(二)

上一篇介绍了Volley的使用,主要接触了Request与RequestQueue这两个类,这篇就来了解一下这两个类的具体实现. Request类图: Request类: Request是一个抽象类,其中的主要属性: mMethod: 请求方法,目前支持GET, POST, PUT, DELETE, HEAD, OPTIONS,TRACE, PATCH方法 mUrl: 请求Url mErrorListener: 错误处理监听器,请求出错时调用 mSequence: 请求的序号,相同优先级的请求在

[Android]Volley源码分析(一)

一. 如何使用Volley? 1. 首先定义一个RequestManager类,用来在Android程序启动时对Volley进行初始化.RequestManager为单例类,因为只有在程序启动时调用,所以不需要考虑并发问题. 1 /** 2 * Manager for the queue 3 */ 4 public class RequestManager { 5 6 /** 7 * 请求队列 8 */ 9 private static RequestQueue mRequestQueue; 1

Android Volley源码分析

今天来顺手分析一下谷歌的volley http通信框架.首先从github上 下载volley的源码, 然后新建你自己的工程以后 选择import module 然后选择volley. 最后还需要更改1个 配置文件 就是我选中的那句话.记得要加.不然会报错.把volley作为一个module 在你的项目中引用的原因是,因为我们要分析源码,需要测试我们心中所想.所以这么做是最方便的. 就相当于eclipse里面的工程依赖. 有关于volley 如何使用的教程 我就不在这写了,请自行谷歌,我们直接看