[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的一些实现,有时间再具体看看。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。