ITKeyword,专注技术干货聚合推荐

注册 | 登录

Part3:Volley传递者原理分析

geekerhw 分享于 2016-07-23

问题产生

  • 我们先看一下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();
                            }
                        }
                    });

问题产生 创建传递者 传递的过程 一个比较重要的细节 问题产生 我们先看一下Volley的使用方法: //第一步,创建一个RequestQueue队列RequestQueue mQueue = Volley.newRequestQueue(context);

相关阅读排行


用户评论

游客

相关内容推荐

最新文章

×

×

请激活账号

为了能正常使用评论、编辑功能及以后陆续为用户提供的其他产品,请激活账号。

您的注册邮箱: 修改

重新发送激活邮件 进入我的邮箱

如果您没有收到激活邮件,请注意检查垃圾箱。