Part3:Volley传递者原理分析
2016-07-23 01:27
323 查看
问题产生
创建传递者
传递的过程
一个比较重要的细节
前面的文章已经分析过了,当我们执行
紧接着看一下
我们再看一下
先不要管别的逻辑,我们直接跟进
在顺便看一下
把上面两段代码和第二步联系起来看,一切都会真相大白了
这个是因为在缓存过期时,会给用户先显示已过期的内容,但是立刻会去网络中请求数据,所以正常的传递逻辑不能少,但必须又包含在异步中请求数据的逻辑,请看入口(在CacheDispatcher中发现缓存失效 后)
创建传递者
传递的过程
一个比较重要的细节
问题产生
我们先看一下Volley的使用方法://第一步,创建一个RequestQueue队列 RequestQueue mQueue = Volley.newRequestQueue(context); //第二步,创建一个具体类型的对象,这里是StringRequest StringRequest stringRequest = new StringRequest("http://www.baidu.com", new Response.Listener<String>() { @Override public void onResponse(String response) { Log.d("TAG", response); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e("TAG", error.getMessage(), error); } }); //第三步,将stringRequest放入queue中 queue.add(stringRequest)
前面的文章已经分析过了,当我们执行
RequestQueue mQueue = Volley.newRequestQueue(context);,它的内部是创建了一个缓存线程和四个网络请求线程,它们会从优先级队列中去取request,如果没有则阻塞,当第三步把相应的请求加入到queue中后,队列中有数据了,线程就会正式执行.那不知道你有没有想过这个问题,请求拿到数据都是在异步线程中的,它到最后是如何跑到onResponse中的(请看上述代码第二步),而且还是这个函数还在主线程中?其实原理非常简单,我们就来稍微分析一下这个类:
ExecutorDelivery(网络请求结果传递类,将数据放到主线程中去处理)
创建传递者
先看一下入口,其实就是第一步时创建,注意Looper.getMainLooper(),它主动绑定了一个主线程中的Looper,这是它能把数据传递到主线程的原因public RequestQueue(Cache cache, Network network) { this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE); } public RequestQueue(Cache cache, Network network, int threadPoolSize) { this(cache, network, threadPoolSize, new ExecutorDelivery(new Handler(Looper.getMainLooper()))); }
紧接着看一下
ExecutorDelivery的构造函数,看完构造函数后如何构造一个传递这就明白了,现在我们分析一下传递的过程
public ExecutorDelivery(final Handler handler) { mResponsePoster = new Executor() { @Override public void execute(Runnable command) { // 所有的Runnable通过绑定主线程Looper的Handler对象最终在主线程执行. handler.post(command); } }; }
传递的过程
传递的入口都是在请求到数据之后,比如CacheDispatcher中得到数据后会调用
mDelivery.postResponse(request, response);方法,我们看一下这个方法,毫无疑问,最终执行的是ResponseDeliveryRunnable中的run方法
@Override public void postResponse(Request<?> request, Response<?> response) { postResponse(request, response, null); } @Override public void postResponse(Request<?> request, Response<?> response, Runnable runnable) { request.markDelivered(); mResponsePoster.execute( new 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) { mRequest = request; mResponse = response; mRunnable = runnable; } @Override public void run() { // 如果request被取消,则不回调用户设置的Listener接口 if (mRequest.isCanceled()) { mRequest.finish("canceled-at-delivery"); return; } // 通过response状态标志,来判断是回调用户设置的Listener接口还是ErrorListener接口 if (mResponse.isSuccess()) { mRequest.deliverResponse(mResponse.result); } else { mRequest.deliverError(mResponse.error); } if (mResponse.intermediate) { mRequest.addMarker("intermediate-response"); } else { // 通知RequestQueue终止该Request请求 mRequest.finish("done"); } //请注意这句语句,后面会讲 if (mRunnable != null) { mRunnable.run(); } } }
先不要管别的逻辑,我们直接跟进
mRequest.deliverResponse(mResponse.result);
/** 将解析的String结果传递给用户的回调接口. */ @Override protected void deliverResponse(String response) { mListener.onResponse(response); }
在顺便看一下
mRequest.deliverError(mResponse.error);
/** 将网络错误传递给回调接口. */ public void deliverError(VolleyError error) { if (mErrorListener != null) { mErrorListener.onErrorResponse(error); } }
把上面两段代码和第二步联系起来看,一切都会真相大白了
一个比较重要的细节
在ResponseDeliveryRunnable中的run方法里最后一段代码,这里会有人疑惑?为什么又跑到异步线程中去了?if (mRunnable != null) { mRunnable.start(); }
这个是因为在缓存过期时,会给用户先显示已过期的内容,但是立刻会去网络中请求数据,所以正常的传递逻辑不能少,但必须又包含在异步中请求数据的逻辑,请看入口(在CacheDispatcher中发现缓存失效 后)
mDelivery.postResponse(request, response, new Runnable() { @Override public void run() { try { mNetworkQueue.put(request); } catch (InterruptedException e) { e.printStackTrace(); } } });
相关文章推荐
- 页面缓存:内存和文件之间的那些事
- 浅析SQL Server中的执行计划缓存(上)
- Enterprise Library for .NET Framework 2.0缓存使用实例
- PowerShell中编程清空IE缓存方法
- PowerShell中使用.NET将程序集加入全局程序集缓存
- C#中缓存的基本用法总结
- Android实现图片异步加载并缓存到本地
- wap开发中如何有效的利用缓存减少消息的传送量
- PHP基于文件存储实现缓存的方法
- smarty缓存用法分析
- 在ASP.NET 2.0中操作数据之五十九:使用SQL缓存依赖项SqlCacheDependency
- 在ASP.NET 2.0中操作数据之五十八:在程序启动阶段缓存数据
- 在ASP.NET 2.0中操作数据之五十七:在分层架构中缓存数据
- 引用全局程序集缓存内的程序集的方法
- asp Response.flush 实时显示进度
- C#实现清除IE浏览器缓存的方法
- ASP.NET缓存管理的几种方法
- PHP文件缓存类实现代码
- 清除aspx页面缓存的程序实现方法
- C#缓存之SqlCacheDependency用法实例总结