专栏名称: 安卓开发精选
伯乐在线旗下账号,分享安卓应用相关内容,包括:安卓应用开发、设计和动态等。
目录
相关文章推荐
stormzhang  ·  年底扣税变多了 ·  2 天前  
鸿洋  ·  细嗅蔷薇,Gradle 系列之 Task 必知必会 ·  3 天前  
stormzhang  ·  来自李子柒的压迫感 ·  3 天前  
鸿洋  ·  理解Android ... ·  4 天前  
51好读  ›  专栏  ›  安卓开发精选

Android 网络编程(4): 从源码解析Volley(上)

安卓开发精选  · 公众号  · android  · 2016-08-21 08:50

正文

(点击上方公众号,可快速关注)


来源:刘望舒   

链接:blog.csdn.net/itachi85/article/details/51104301



1.Volley结构图



从上图可以看到Volley分为三个线程,分别是主线程、缓存调度线程、和网络调度线程,首先请求会加入缓存队列,如果发现可以找到相应的缓存结果就直接读取缓存并解析,然后回调给主线程;如果在缓存中没有找到结果,则将这条请求加入到网络队列中,然后发送HTTP请求,解析响应并写入缓存,并回调给主线程。


2.从RequestQueue入手


我们都知道使用Volley之前首先要创建RequestQueue:


RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());


这也是volley运作的入口,看看newRequestQueue:


public static RequestQueue newRequestQueue(Context context) {

        return newRequestQueue(context, (HttpStack)null);

    }

 

public static RequestQueue newRequestQueue(Context context, HttpStack stack) {

        return newRequestQueue(context, stack, -1);

    }


连续调用了两个重载函数,最终调用的是:


public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {

        File cacheDir = new File(context.getCacheDir(), "volley");

        String userAgent = "volley/0";

 

        try {

            String network = context.getPackageName();

            PackageInfo queue = context.getPackageManager().getPackageInfo(network, 0);

            userAgent = network + "/" + queue.versionCode;

        } catch (NameNotFoundException var7) {

            ;

        }

 

        if(stack == null) {

            if(VERSION.SDK_INT >= 9) {

                stack = new HurlStack();

            } else {

                stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));

            }

        }

 

        BasicNetwork network1 = new BasicNetwork((HttpStack)stack);

        RequestQueue queue1;

        if(maxDiskCacheBytes 1) {

            queue1 = new RequestQueue(new DiskBasedCache(cacheDir), network1);

        } else {

            queue1 = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network1);

        }

 

        queue1.start();

        return queue1;

    }


可以看到如果android版本大于等于2.3则调用基于HttpURLConnection的HurlStack,否则就调用基于HttpClient的HttpClientStack。并创建了RequestQueue,调用了start()方法:


public void start() {

        this.stop();

        this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery);

        this.mCacheDispatcher.start();

 

        for(int i = 0; i this.mDispatchers.length; ++i) {

            NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery);

            this.mDispatchers[i] = networkDispatcher;

            networkDispatcher.start();

        }

 

    }


CacheDispatcher是缓存调度线程,并调用了start()方法,在循环中调用了NetworkDispatcher的start()方法,NetworkDispatcher是网络调度线程,默认情况下mDispatchers.length为4,默认开启了4个网络调度线程,也就是说有5个线程在后台运行并等待请求的到来。接下来我们创建各种的Request,并调用RequestQueue的add()方法:


public Request add(Request request) {

        request.setRequestQueue(this);

        Set var2 = this.mCurrentRequests;

        synchronized(this.mCurrentRequests) {

            this.mCurrentRequests.add(request);

        }

 

        request.setSequence(this.getSequenceNumber());

        request.addMarker("add-to-queue");

        //如果不能缓存,则将请求添加到网络请求队列中

        if(!request.shouldCache()) {

            this.mNetworkQueue.add(request);

            return request;

        } else {

            Map var8 = this.mWaitingRequests;

            synchronized(this.mWaitingRequests) {

                String cacheKey = request.getCacheKey();

 

       //之前是否有执行相同的请求且还没有返回结果的,如果有的话将此请求加入mWaitingRequests队列,不再重复请求

                if(this.mWaitingRequests.containsKey(cacheKey)) {

                    Object stagedRequests = (Queue)this.mWaitingRequests.get(cacheKey);

                    if(stagedRequests == null) {

                        stagedRequests = new LinkedList();

                    }

 

                    ((Queue)stagedRequests).add(request);

                    this.mWaitingRequests.put(cacheKey, stagedRequests);

                    if(VolleyLog.DEBUG) {

                        VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", new Object[]{cacheKey});

                    }

                } else {

   //没有的话就将请求加入缓存队列mCacheQueue,同时加入mWaitingRequests中用来做下次同样请求来时的重复判断依据

                    this.mWaitingRequests.put(cacheKey, (Object)null);

                    this.mCacheQueue.add(request);

                }

 

                return request;

            }

        }

    }


通过判断request.shouldCache(),来判断是否可以缓存,默认是可以缓存的,如果不能缓存,则将请求添加到网络请求队列中,如果能缓存就判断之前是否有执行相同的请求且还没有返回结果的,如果有的话将此请求加入mWaitingRequests队列,不再重复请求;没有的话就将请求加入缓存队列mCacheQueue,同时加入mWaitingRequests中用来做下次同样请求来时的重复判断依据。


从上面可以看出RequestQueue的add()方法并没有做什么请求网络或者对缓存进行操作。当将请求添加到网络请求队列或者缓存队列时,这时在后台的网络调度线程和缓存调度线程轮询各自的请求队列发现有请求任务则开始执行,我们先看看缓存调度线程。


3.CacheDispatcher缓存调度线程


CacheDispatcher的run()方法:


public void run() {

        if(DEBUG) {

            VolleyLog.v("start new dispatcher", new Object[0]);

        }

        //线程优先级设置为最高级别

        Process.setThreadPriority(10);

        this.mCache.initialize();

 

        while(true) {

            while(true) {

                while(true) {

                    while(true) {

                        try {

                        //获取缓存队列中的一个请求

                            final Request e = (Request)this.mCacheQueue.take();

                            e.addMarker("cache-queue-take");

                            //如果请求取消了则将请求停止掉

                            if(e.isCanceled()) {

                                e.finish("cache-discard-canceled");

                            } else {

                            //查看是否有缓存的响应

                                Entry entry = this.mCache.get(e.getCacheKey());

                                //如果缓存响应为空,则将请求加入网络请求队列

                                if(entry == null) {

                                    e.addMarker("cache-miss");

                                    this.mNetworkQueue.put(e);

                                //判断缓存响应是否过期    

                                } else if(!entry.isExpired()) {

                                    e.addMarker("cache-hit");

                                    //对数据进行解析并回调给主线程

                                    Response response = e.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));

    e.addMarker("cache-hit-parsed");

                                    if(!entry.refreshNeeded()) {

                                        this.mDelivery.postResponse(e, response);

                                    } else {

                                        e.addMarker("cache-hit-refresh-needed");

                                        e.setCacheEntry(entry);

                                        response.intermediate = true;

                                        this.mDelivery.postResponse(e, response, new Runnable() {

                                            public void run() {

                                                try {

                                                    CacheDispatcher.this.mNetworkQueue.put(e);

                                                } catch (InterruptedException var2) {

                                                    ;

                                                }

 

                                            }

                                        });

                                    }

                                } else {

                                    e.addMarker("cache-hit-expired");

                                    e.setCacheEntry(entry);

                                    this.mNetworkQueue.put(e);

                                }

                            }


接下文

------------- 推荐 ------------


范品社推出的极客T恤,含程序员、电影、美剧和物理题材,面料舒适、100%纯棉,有黑、白、灰、藏青色,单件 ¥59.9、两件减¥12、四件减¥28、六件减¥42,详见网店商品页介绍。



(上面为部分 T 恤款式)


网店地址:https://fanpinshe.taobao.com


淘口令:复制以下红色内容,然后打开手淘即可购买


范品社,使用¥极客T恤¥抢先预览(长按复制整段文案,打开手机淘宝即可进入活动内容)