Volley 源码分析

Volley基本使用

        //声明一个请求队列,请求队列最好全局唯一。
        RequestQueue mQueue = Volley.newRequestQueue(context);
        //请求的错误回调
        Response.ErrorListener errorListener = new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                  ...
            }
        };
        //请求的正确回调
        Response.Listener listener = new Response.Listener() {
            @Override
            public void onResponse(Object o) {


            }
        };
        //封装好的请求
        StringRequest stringRequest = new StringRequest(Request.Method.POST, url, listener, errorListener) {

                @Override
                protected Map<String, String> getParams() throws AuthFailureError {
                    // TODO Auto-generated method stub
                    if (request.isEmpty())
                        return super.getParams();
                    else {
                        return request;
                    }
                }

            };
        //将封装好的请求加入到请求队列中去
        mQueue.add(stringRequest);


整体框架

这里写图片描述

Volley整体框架如上图所示,是一个典型的生产者消费者模式。主要可以分成三个部分,一个是封装好的Request,包含请求的类型等等,然后将其投入到RequestQueue中,之后有一个用于分发请求的线程Dispatcher,进行网络请求的执行和回调。下面分部分分析:
关键类的UML图,主要四个类为:请求Request、响应Response、网络执行工人线程NetWorkExecutor、结果UI线程回调ResponseDelivery
这里写图片描述


Request

这里写图片描述
抽象父类Request,有多个不同种类的Request。StringRequest的构造器调用父类构造器,在Request中存储http请求的方式,Url和失败回调的地址。成功的回调是一个泛型接口

    public interface Listener<T> {
        /** Called when a response is received. */
        public void onResponse(T response);
    }

这里我们将类型参数赋值为String,然后将接口实现并存储在StringRequest中的mListener中。在Request中另有抽象方法parseNetworkResponse和deliverResponse,子类实现,后面消费者消费Request时候,调用parseNetworkResponse解析原始的响应,然后调用deliverResponse分发给UI线程。
StringRequest的具体实现:

@Override
    protected Response<String> parseNetworkResponse(NetworkResponse response) {
        String parsed;
        try {
            parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
        } catch (UnsupportedEncodingException e) {
            parsed = new String(response.data);
        }
        return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
    }

将网络响应的报文体直接按字符串转换,封装进Response返回。

    @Override
    protected void deliverResponse(String response) {
        if (mListener != null) {
            mListener.onResponse(response);
        }
    }

然后将Respone通过设置的回调接口,调用来处理客户端想要处理的逻辑。
这种典型的写法启示我们,在实现异步逻辑的时候,可以将客户端想要的逻辑利用接口实现,然后封装进一个实体中,当线程完成工作后调用这个实体存储的接口实现,从而客户端可以异步实现逻辑。

RequestQueue

大致了解了封装的实体类Request后,来看一下生产者和消费者连接的部分RequestQueue。
调用Volley类中静态方法newRequestQueue来实例化一个RequestQueue

    public RequestQueue(Cache cache, Network network, int threadPoolSize,
            ResponseDelivery delivery) {
        mCache = cache;
        mNetwork = network;
        mDispatchers = new NetworkDispatcher[threadPoolSize];
        mDelivery = delivery;
    }

构造器中,cache是缓存文件目录,network中封装了如何将Request转化为http请求的方法performRequest,类似于策略模式。Dispatchers就是从队列中拿出Request进行网络请求的workerThread消费者,delivery默认值是new ExecutorDelivery(new Handler(Looper.getMainLooper())),其中的handler和UI线程的Looper相连,从而可以通过handler向UI线程的消息队列发送消息更改UI,delivery也就是结果处理后的界面更改回调。
综上,RequestQueue中封装了Request转换为网络请求的方法,分发请求的工作线程,将结果发送给UI的传递者。
调用requestQueue.start()后,启动缓存线程和网络请求线程,主要分析网络请求部分:

        for (int i = 0; i < mDispatchers.length; i++) {
            NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
                    mCache, mDelivery);
            mDispatchers[i] = networkDispatcher;
            networkDispatcher.start();
        }

mDispachers是一个数组,类似线程池存储着工人线程。NetworkDispatcher是worker thread,

    public void quit() {
        mQuit = true;
        interrupt();
    }

quit方法通过interrupt和标志位中断一个线程。

@Override
    public void run() {
        //设置当前线程为后台线程,减少对于UI线程渲染的影响
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        Request<?> request;
        while (true) {
            long startTimeMs = SystemClock.elapsedRealtime();
            // release previous request object to avoid leaking request object when mQueue is drained.
            request = null;
            try {
                // Take a request from the queue.
                request = mQueue.take();
            } catch (InterruptedException e) {
                // We may have been interrupted because it was time to quit.
                //检查标志位,看队列是否结束
                if (mQuit) {
                    return;
                }
                continue;
            }

            try {

                // If the request was cancelled already, do not perform the
                // network request.
                if (request.isCanceled()) {
                    request.finish("network-discard-cancelled");
                    continue;
                }


                // 这里调用网络请求策略network,将Request转化为网络请求处理。获得响应封装。
                NetworkResponse networkResponse = mNetwork.performRequest(request);

                //304缓存处理。没有修改,不进行http请求维持原状。
                if (networkResponse.notModified && request.hasHadResponseDelivered()) {
                    request.finish("not-modified");
                    continue;
                }

                // 将原始的网络请求解析,这里是按照StringRequest的方式解析。
                Response<?> response = request.parseNetworkResponse(networkResponse);

                //缓存相关
                if (request.shouldCache() && response.cacheEntry != null) {
                    mCache.put(request.getCacheKey(), response.cacheEntry);
                    request.addMarker("network-cache-written");
                }

                // delivery,分发更改UI
                request.markDelivered();
                mDelivery.postResponse(request, response);
            } catch (VolleyError volleyError) {
                volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
                parseAndDeliverNetworkError(request, volleyError);
            } catch (Exception e) {
                VolleyLog.e(e, "Unhandled exception %s", e.toString());
                VolleyError volleyError = new VolleyError(e);
                volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
                mDelivery.postError(request, volleyError);
            }
        }
    }

Delivery

分发部分的实现

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

其中

        mResponsePoster = new Executor() {
            @Override
            public void execute(Runnable command) {
                handler.post(command);
            }
        };

ResponseDeliveryRunnable是给UI线程的Handler发送的Runnable,也就是说这部分是执行在UI线程上的,其中逻辑部分:

@SuppressWarnings("unchecked")
        @Override
        public void run() {
            // If this request has canceled, finish it and don't deliver.
            if (mRequest.isCanceled()) {
                mRequest.finish("canceled-at-delivery");
                return;
            }

            // 调用我们定义的Request中的listener回调
            if (mResponse.isSuccess()) {
                mRequest.deliverResponse(mResponse.result);
            } else {
                mRequest.deliverError(mResponse.error);
            }

            // If this is an intermediate response, add a marker, otherwise we're done
            // and the request can be finished.
            if (mResponse.intermediate) {
                mRequest.addMarker("intermediate-response");
            } else {
                mRequest.finish("done");
            }

            // If we have been provided a post-delivery runnable, run it.
            if (mRunnable != null) {
                mRunnable.run();
            }
       }

可以看在,最初在Request中封装的更改UI的listener,在mRequest.deliverResponse(mResponse.result); 被异步调用并执行,并且通过ExecutorDelivery确保在UI线程中执行,ExecutorDelivery类似命令模式,dispatcher负责网络部分,Delivery负责UI部分,确保收到的每个Request响应的回调执行在UI线程中。


总结

作为生产者-消费者模式,客户端可以将网络请求的处理方式,获取响应后的处理逻辑封装进Request,然后放进RequestQueue中。对于一个全局的RequestQueue,维护一个工作线程池,利用多个线程从队列中去除Request去执行网络请求,根据Request中封装的网络请求方法获取Response后,将结果给Delivery。然后通过Delivery分发给UI线程,调用Request中更新的UI处理逻辑。
对比传统的通过新建线程实现网络请求的方式,volley采用的方式不仅逻辑清晰、易于管理,同时将线程维护、UI更新这部分不易发生变化的工作封装,用户也可通过继承Request实现扩展,增强了可维护性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值