volley网络通信框架研究

volley的使用方式大致如下:

<span style="font-size:18px;"><span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">	</span>RequestQueue </span><span style="font-family: Arial, Helvetica, sans-serif;">mRequestQueue = Volley.newRequestQueue(mContext.getApplicationContext());</span></span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-size:18px;"></span></span><pre name="code" class="java"><span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">	</span>XXRequest  request = new XXRequest(Method.XX, "URL", </span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">		</span>new Response,Listener<XXX>(){ </span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">			</span>@Override</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">			</span>public void onResponse(XXX response){</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">				</span>//do something</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">			</span>}</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">		</span>}, new Response.ErrorListener(){</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">			</span>@Override</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">			</span>public void onErrorResponse(VolleyError error){</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">				</span>//do something</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">			</span>}</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">		</span>});</span>

 
<span style="font-size:18px;"><span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">	</span>mRequestQueue.add(</span><span style="font-family: Arial, Helvetica, sans-serif;">request </span><span style="font-family: Arial, Helvetica, sans-serif;">);</span></span>
看了几遍volley的源代码,大致记录下volley的工作过程。

1. Volley.newRequestQueue(Context context)创建mRequestQueue并调用其start()函数,start函数中开启若干个线程,包括一个CacheDispatcher,若干个NetworkDispatcher,这些线程会一直在后台运行。


2. mRequestQueue.add(request),首先将request加入CurrentRequest(一个HashSet,注意request finish时会将其从该Set中移除),在判断request是否需要缓存,如果不需要,直接加入NetworkQueue,

判断WaitingRequests(一个HashMap)是否已经有URL相同的request在通信中,如下:

<span style="font-size:18px;">synchronized (mWaitingRequests) {
            String cacheKey = request.getCacheKey();</span>
<span style="font-size:18px;"><span style="white-space:pre">	</span>    //判断是否在WaitingRequests中
            if (mWaitingRequests.containsKey(cacheKey)) {
                // There is already a request in flight. Queue up.
                Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey);
                if (stagedRequests == null) {
                    stagedRequests = new LinkedList<Request<?>>();
                }
                stagedRequests.add(request);
                mWaitingRequests.put(cacheKey, stagedRequests);
                if (VolleyLog.DEBUG) {
                    VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
                }
            } else {
                // Insert 'null' queue for this cacheKey, indicating there is now a request in
                // flight.
                mWaitingRequests.put(cacheKey, null);
                mCacheQueue.add(request);
            }
            return request;
        }</span>
如果有则则将其加入对应key的stagedRequests中(表示已经有相同的request在执行),否则将其加入CacheQueue


3. CahceDispather从CacheQueue中取request,判断是否在缓存中,如果request.getCacheKey()对应的Cache.Entry为null或者该entry失效了,将其加入NetworkQueue,否则根据这些信息生成response,如下:

<span style="font-size:18px;">Response<?> response = request.parseNetworkResponse(
                        new NetworkResponse(entry.data, entry.responseHeaders));</span>
然后判断request是否需要更新,不需要直接:

<span style="font-size:18px;">mDelivery.postResponse(request, response);</span>

mDelivery是一个继承自Executor的ResponseDelivery类的对象,实际则为ExecutorDelivery,实际这个方法开启新线程又调用了request的方法:

<span style="font-size:18px;">if (mResponse.isSuccess()) {
                mRequest.deliverResponse(mResponse.result);
            } else {
                mRequest.deliverError(mResponse.error);
            }</span>
而这两个方法中执行的便是最初传入的两个Listener中的方法,很明显此时不在主线程中,如果要根据返回值跟新UI,最好传入一个Handler进行操作

如果需要更新,如下:
<span style="font-size:18px;">mDelivery.postResponse(request, response, new Runnable() {
                        @Override
                        public void run() {
                            try {
                                mNetworkQueue.put(request);
                            } catch (InterruptedException e) {
                                // Not much we can do about this.
                            }
                        }
                    });</span>
多开启一个线程将将request加入NetworkQueue中,很明显不可能一开始Cache中就有数据,最初的数据都是通过NetworkDispatcher通过网络获得的,


4.NetworkDispatcher从NetworkQueue中获取request,首先:

<span style="font-size:18px;">NetworkResponse networkResponse = mNetwork.performRequest(request);
</span>
这时Network起作用了,它里面有一个HttpStack,这一步得追溯到最初Volley对RequestQueue的建立:
<span style="font-size:18px;">if (stack == null) {
            if (Build.VERSION.SDK_INT >= 9) {
                stack = new HurlStack();
            } else {
                // Prior to Gingerbread, HttpUrlConnection was unreliable.
                // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
                stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
            }
        }

        Network network = new BasicNetwork(stack);</span>
其中stack即为HttpStack实例,HurlStack和HttpClientStack都继承自HttpStack(主要讨论volley工作流程,网络我也不太懂),显然此处获得了NetworkResponse后,后续工作就与步骤3中差不多了,如下:

<span style="font-size:18px;">Response<?> response = request.parseNetworkResponse(networkResponse);
                request.addMarker("network-parse-complete");

                // Write to cache if applicable.
                // TODO: Only update cache metadata instead of entire record for 304s.
                if (request.shouldCache() && response.cacheEntry != null) {
                    mCache.put(request.getCacheKey(), response.cacheEntry);
                    request.addMarker("network-cache-written");
                }

                // Post the response back.
                request.markDelivered();
                mDelivery.postResponse(request, response);</span>
注意如果需要缓存的话,需要将request对应的CacheKey和cacheEntry加入Cache中,而markDelivered抑制request生命周期中相同的反应




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值