Android网络编程(七)源码解析OkHttp前篇[请求网络]

相关文章
Android网络编程系列

前言

学会了OkHttp3的用法后,我们当然有必要来了解下OkHttp3的源码,当然现在网上的文章很多,我仍旧希望我这一系列文章篇是最简洁易懂的。

查看更多

分享到 评论

Java并发编程(六)阻塞队列

前言

Android多线程(一)线程池这篇文章时,当我们要创建ThreadPoolExecutor的时候需要传进来一个类型为BlockingQueue的参数,它就是阻塞队列,在这一篇文章里我们会介绍阻塞队列的定义、种类、实现原理以及应用。

查看更多

分享到 评论

设计模式(八)外观模式

相关文章
设计模式系列

1.外观模式简介

外观模式介绍

当我们开发Android的时候,无论是做SDK还是封装API,我们大多都会用到外观模式,它通过一个外观类使得整个系统的结构只有一个统一的高层接口,这样能降低用户的使用成本。

外观模式定义

为系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得子系统更加容易使用。

外观模式结构图

  • Facade:外观类,知道哪些子系统类负责处理请求,将客户端的请求代理给适当的子系统对象。
  • Subsystem:子系统类,实现子系统的功能,处理外观类指派的任务,注意子系统类不含有外观类的引用。

2.外观模式的简单实现

在上一篇设计模式之装饰模式我们举了武侠的例子,这一篇我们还举武侠的例子,首先我们把武侠张无忌当作一个系统,他作为一个武侠,他本身分为三个系统分别是招式、内功和经脉。

子系统类(Subsystem)

我们知道张无忌的三个系统分别是招式、内功和经脉。那我们来创建它们:

/**
 * 子系统招式
 */
public class ZhaoShi {
    public void TaiJiQuan(){
        System.out.print("使用着招式太极拳");
    }
    public void QiShangQuan(){
        System.out.print("使用招式七伤拳");
    }
    public void ShengHuo(){
        System.out.print("使用招式圣火令");
    }
}


/**
 * 子系统内功
 */
public class NeiGong {
    public void JiuYang(){
        System.out.print("使用九阳神功");
    }
    public void QianKun(){
        System.out.print("使用乾坤大挪移");
    }
}
/**
 * 子系统经脉
 */
public class JingMai {
    public void jingmai(){
        System.out.print("开启经脉");
    }
}

张无忌有很多的武学和内功,怎么将他们搭配,并对外界隐藏呢,我们接下来看看外观类:

外观类(Facade)

这里的外观类就是张无忌,他负责将自己的招式、内功和经脉通过不同的情况合理的运用:

/**
 * 外观类张无忌
 */
public class ZhangWuJi {
    private JingMai jingMai;
    private ZhaoShi zhaoShi;
    private NeiGong neiGong;

    public ZhangWuJi(){
        jingMai=new JingMai();
        zhaoShi=new ZhaoShi();
        neiGong=new NeiGong();
    }
    /**
     * 使用乾坤大挪移
     */
    public void Qiankun(){
        jingMai.jingmai();//开启经脉
        neiGong.QianKun();//使用内功乾坤大挪移

    }
    /**
     * 使用七伤拳
     */
    public void QiShang(){
        jingMai.jingmai(); //开启经脉
        neiGong.JiuYang();//使用内功九阳神功
        zhaoShi.QiShangQuan();//使用招式七伤拳
    }
}

初始化外观类的同时将各个子系统类创建好。很明显张无忌很好的将自身的各个系统搭配好,如果使用七伤拳的话就需要开启经脉、使用内功九阳神功接下来使用招式七伤拳,如果不开经脉或者使用九阳神功的话那么七伤拳的威力会大打折扣。

客户端调用

public class Test {
    public static void main(String[] args){
        ZhangWuJi zhangWuJi=new ZhangWuJi();
        //张无忌使用乾坤大挪移
        zhangWuJi.Qiankun();
        //张无忌使用七伤拳
        zhangWuJi.QiShang();
    }
}

当张无忌使用乾坤大挪移或者七伤拳的时候,比武的对手显然不知道张无忌本身运用了什么,同时张无忌也不需要去重新计划使用七伤拳的时候需要怎么做,他已经早就计划好了。如果每次使用七伤拳或者乾坤大挪移时都要计划怎么做很显然会增加成本并贻误战机。另外张无忌也可以改变自己的内功、招式和经脉,这些都是对比武的对手有所隐藏的。
外观模式本身就是将子系统的逻辑和交互隐藏起来,为用户提供一个高层次的接口,使得系统更加易用,同时也隐藏了具体的实现,这样即使具体的子系统发生了变化,用户也不会感知到。

3.外观模式使用场景

  • 构建一个有层次结构的子系统时,使用外观模式定义子系统中每层的入口点,如果子系统之间是相互依赖的,则可以让他们通过外观接口进行通信,减少子系统之间的依赖关系。
  • 子系统往往会因为不断的重构演化而变得越来越复杂,大多数的模式使用时也会产生很多很小的类,这给外部调用他们的用户程序带来了使用的困难,我们可以使用外观类提供一个简单的接口,对外隐藏子系统的具体实现并隔离变化。
  • 当维护一个遗留的大型系统时,可能这个系统已经非常难以维护和拓展,但因为它含有重要的功能,新的需求必须依赖于它,则可以使用外观类,来为设计粗糙或者复杂的遗留代码提供一个简单的接口,让新系统和外观类交互,而外观类负责与遗留的代码进行交互。
分享到 评论

Java并发编程(五)ConcurrentHashMap的实现原理和源码分析

前言

在Java1.5中,并发编程大师Doug Lea给我们带来了concurrent包,而该包中提供的ConcurrentHashMap是线程安全并且高效的HashMap,本节我们就来研究下ConcurrentHashMap是如何保证线程安全的同时又能高效的操作。

查看更多

分享到 评论

Android View体系(十一)自定义ViewGroup

前言

此前讲了很多,终于可以讲到这一节了,本文的例子是一个自定义的ViewGroup,左右滑动切换不同的页面,类似一个特别简化的ViewPager,这篇文章会涉及到这个系列的很多文章的内容比如View的measure、layout和draw流程,view的滑动等等,所以对View体系不大了解的同学看这篇文章前可以先从头阅读本系列的其他文章,再来看这篇文章效果会更好些。需要注意的是我们知道要实现一个自定义的ViewGroup是很复杂的,这个看看LineraLayout等源码我们就会知道,这里我们只需要把主要的功能实现就好了。

查看更多

分享到 评论

Java并发编程(四)Java内存模型

前言

此前我们讲到了线程、同步以及volatile关键字,对于Java的并发编程我们有必要了解下Java的内存模型,因为Java线程之间的通信对于工程师来言是完全透明的,内存可见性问题很容易使工程师们觉得困惑,这篇文章我们来主要的讲下Java内存模型的相关概念。

查看更多

分享到 评论

Android View体系(十)自定义组合控件

前言

上一篇我们讲到了自定义View,接着我们来讲讲常用的自定义组合控件,自定义组合控件就是多个控件组合起来成为一个新的控件,主要用来解决多次重复的使用同一类型的布局。比如我们应用的顶部的标题栏,还有弹出的固定样式的dialog,这些都是常用的,所以把他们所需要的控件组合起来重新定义成一个新的控件。

查看更多

分享到 评论

设计模式(七)装饰模式

相关文章
设计模式系列

1.装饰模式简介

装饰模式介绍

装饰模式是结构型设计模式之一,不必改变类文件和使用继承的情况下,动态地扩展一个对象的功能,是继承的替代方案之一。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

定义

动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。

装饰模式结构图

  • Component:抽象组件,给对象动态的添加职责。
  • ConcreteComponent:组件具体实现类。
  • Decorator:抽象装饰者,继承Component,从外类来拓展Component类的功能,但对于Component来说无需知道Decorator的存在。
  • ConcreteDecorator:装饰者具体实现类。

2.装饰模式的简单实现

装饰模式在现实生活中有很多例子,比如给一个人穿上各种衣服,给一幅画涂色上框等等,这次我要举得例子有些不同,举一个武侠修炼武功的例子:杨过本身就会全真剑法,有两位武学前辈洪七公和欧阳锋分别传授杨过打狗棒法和蛤蟆功,这样杨过除了会全真剑法还会打狗棒法和蛤蟆功。

抽象组件(Component)

作为武侠肯定要会使用武功的,我们先定义一个武侠的抽象类,里面有使用武功的抽象方法:

public abstract class Swordsman {
    /**
     * Swordsman武侠有使用武功的抽象方法
     */
    public abstract void attackMagic();
}

组件具体实现类(ConcreteComponent)

被装饰的具体对象,在这里就是被教授武学的具体的武侠,他就是杨过,杨过作为武侠当然也会武学,虽然不怎么厉害:

public class YangGuo extends Swordsman{
    @Override
    public void attackMagic() {
        //杨过初始的武学是全真剑法
        System.out.println("杨过使用全真剑法");
    }
}

抽象装饰者(Decorator)

抽象装饰者保持了一个对抽象组件的引用,方便调用被装饰对象中的方法。在这个例子中就是武学前辈要持有武侠的引用,方便教授他武学并“融会贯通”:

public abstract class Master extends Swordsman{
    private Swordsman mSwordsman;

    public Master(Swordsman mSwordsman){
        this.mSwordsman=mSwordsman;
    }
    @Override
    public void attackMagic() {
        mSwordsman.attackMagic();
    }
}

装饰者具体实现类(ConcreteDecorator)

这个例子中用两个装饰者具体实现类,分别是洪七公和欧阳锋,他们负责来传授杨过新的武功:

public class HongQiGong extends Master {
    public HongQiGong(Swordsman mSwordsman) {
        super(mSwordsman);
    }
    public void teachAttackMagic(){
        System.out.println("洪七公教授打狗棒法");
        System.out.println("杨过使用打狗棒法");
    }
    @Override
    public void attackMagic() {
        super.attackMagic();
        teachAttackMagic();
    }
}
public class OuYangFeng extends Master {
    public OuYangFeng(Swordsman mSwordsman) {
        super(mSwordsman);
    }
    public void teachAttackMagic(){
        System.out.println("欧阳锋教授蛤蟆功");
        System.out.println("杨过使用蛤蟆功");
    }
    @Override
    public void attackMagic() {
        super.attackMagic();
        teachAttackMagic();
    }
}

客户端调用

经过洪七公和欧阳锋的教导,杨过除了初始武学全真剑法又学会了打狗棒法和蛤蟆功:

public class Client {
    public static void main(String[] args){
        //创建杨过
        YangGuo mYangGuo=new YangGuo();
        //洪七公教授杨过打狗棒法,杨过会了打狗棒法
        HongQiGong mHongQiGong=new HongQiGong(mYangGuo);
        mHongQiGong.attackMagic();

        //欧阳锋教授杨过蛤蟆功,杨过学会了蛤蟆功
        OuYangFeng mOuYangFeng=new OuYangFeng(mYangGuo);
        mOuYangFeng.attackMagic();
    }
}

3.装饰模式的优缺点和使用场景

优点

  • 通过组合而非继承的方式,动态的来扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。
  • 有效避免了使用继承的方式扩展对象功能而带来的灵活性差,子类无限制扩张的问题。
  • 具体组件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体组件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。

缺点

  • 装饰链不能过长,否则会影响效率。
  • 因为所有对象都是继承于Component,所以如果Component内部结构发生改变,则不可避免地影响所有子类(装饰者和被装饰者),如果基类改变,势必影响对象的内部。
  • 比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐,所以只在必要的时候使用装饰者模式。

使用场景

  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
  • 需要动态地给一个对象增加功能,这些功能可以动态的撤销。
  • 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。

4.装饰模式和代理模式

在上一篇文章设计模式之代理模式中我们讲到了代理模式,你会觉得代理模式和装饰模式有点像,都是持有了被代理或者被装饰对象的引用。它们两个最大的不同就是装饰模式对引用的对象增加了功能,而代理模式只是对引用对象进行了控制却没有对引用对象本身增加功能。

分享到 评论

Android网络编程(六)OkHttp3用法全解析

1674999-9b8a9e0353734231_副本.png
相关文章
Android网络编程系列

前言

上一篇介绍了OkHttp2.x的用法,这一篇文章我们来对照OkHttp2.x版本来看看,OkHttp3使用起来有那些变化。当然,看这篇文章前建议看一下前一篇文章Android网络编程(五)OkHttp2.x用法全解析

查看更多

分享到 评论

Android网络编程(五)OkHttp2.x用法全解析

相关文章
Android网络编程系列

前言

讲完了Volley,我们接下来看看目前比较火的网络框架OkHttp, 它处理了很多网络疑难杂症:会从很多常用的连接问题中自动恢复。如果您的服务器配置了多个IP地址,当第一个IP连接失败的时候,OkHttp会自动尝试下一个IP,此外OkHttp还处理了代理服务器问题和SSL握手失败问题。

查看更多

分享到 评论

Android网络编程(四)从源码解析Volley

相关文章
Android网络编程系列

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 <T> Request<T> add(Request<T> 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);
                            }
                        }
                    } catch (InterruptedException var4) {
                        if(this.mQuit) {
                            return;
                        }
                    }
                }
            }
        }
    }
}

static {
    DEBUG = VolleyLog.DEBUG;
}

看到四个while循环有些晕吧,让我们挑重点的说,首先从缓存队列取出请求,判断是否请求是否被取消了,如果没有则判断该请求是否有缓存的响应,如果有并且没有过期则对缓存响应进行解析并回调给主线程。接下来看看网络调度线程。

4.NetworkDispatcher网络调度线程

NetworkDispatcher的run()方法:

public void run() {
       Process.setThreadPriority(10);

       while(true) {
           long startTimeMs;
           Request request;
           while(true) {
               startTimeMs = SystemClock.elapsedRealtime();

               try {
               //从队列中取出请求
                   request = (Request)this.mQueue.take();
                   break;
               } catch (InterruptedException var6) {
                   if(this.mQuit) {
                       return;
                   }
               }
           }

           try {
               request.addMarker("network-queue-take");
               if(request.isCanceled()) {
                   request.finish("network-discard-cancelled");
               } else {
                   this.addTrafficStatsTag(request);
                   //请求网络
                   NetworkResponse e = this.mNetwork.performRequest(request);
                   request.addMarker("network-http-complete");
                   if(e.notModified && request.hasHadResponseDelivered()) {
                       request.finish("not-modified");
                   } else {
                       Response volleyError1 = request.parseNetworkResponse(e);
                       request.addMarker("network-parse-complete");
                       if(request.shouldCache() && volleyError1.cacheEntry != null) {                         
                           //将响应结果存入缓存
                           this.mCache.put(request.getCacheKey(), volleyError1.cacheEntry);
                           request.addMarker("network-cache-written");
                       }

                       request.markDelivered();
                       this.mDelivery.postResponse(request, volleyError1);
                   }
               }
           } catch (VolleyError var7) {
               var7.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
               this.parseAndDeliverNetworkError(request, var7);
           } catch (Exception var8) {
               VolleyLog.e(var8, "Unhandled exception %s", new Object[]{var8.toString()});
               VolleyError volleyError = new VolleyError(var8);
               volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
               this.mDelivery.postError(request, volleyError);
           }
       }
   }

网络调度线程也是从队列中取出请求并且判断是否被取消了,如果没取消就去请求网络得到响应并回调给主线程。请求网络时调用this.mNetwork.performRequest(request),这个mNetwork是一个接口,实现它的类是BasicNetwork,我们来看看BasicNetwork的performRequest()方法:

  public NetworkResponse performRequest(Request<?> request) throws VolleyError {
        long requestStart = SystemClock.elapsedRealtime();

        while(true) {
            HttpResponse httpResponse = null;
            Object responseContents = null;
            Map responseHeaders = Collections.emptyMap();

            try {
                HashMap e = new HashMap();
                this.addCacheHeaders(e, request.getCacheEntry());
                httpResponse = this.mHttpStack.performRequest(request, e);
                StatusLine statusCode1 = httpResponse.getStatusLine();
                int networkResponse1 = statusCode1.getStatusCode();
                responseHeaders = convertHeaders(httpResponse.getAllHeaders());
                if(networkResponse1 == 304) {
                    Entry requestLifetime2 = request.getCacheEntry();
                    if(requestLifetime2 == null) {
                        return new NetworkResponse(304, (byte[])null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
                    }

                    requestLifetime2.responseHeaders.putAll(responseHeaders);
                    return new NetworkResponse(304, requestLifetime2.data, requestLifetime2.responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
                }


...省略

从上面可以看到在12行调用的是HttpStack的performRequest()方法请求网络,接下来根据不同的响应状态码来返回不同的NetworkResponse。另外HttpStack也是一个接口,实现它的两个类我们在前面已经提到了就是HurlStack和HttpClientStack。让我们再回到NetworkDispatcher,请求网络后,会将响应结果存在缓存中,如果响应结果成功则调用this.mDelivery.postResponse(request, volleyError1)来回调给主线程。来看看Delivery的postResponse()方法:

public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
       request.markDelivered();
       request.addMarker("post-response");
       this.mResponsePoster.execute(new ExecutorDelivery.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) {
           this.mRequest = request;
           this.mResponse = response;
           this.mRunnable = runnable;
       }

       public void run() {
           if(this.mRequest.isCanceled()) {
               this.mRequest.finish("canceled-at-delivery");
           } else {
               if(this.mResponse.isSuccess()) {
                   this.mRequest.deliverResponse(this.mResponse.result);
               } else {
                   this.mRequest.deliverError(this.mResponse.error);
               }

               if(this.mResponse.intermediate) {
                   this.mRequest.addMarker("intermediate-response");
               } else {
                   this.mRequest.finish("done");
               }

               if(this.mRunnable != null) {
                   this.mRunnable.run();
               }

           }
       }
   }

第17行调用了this.mRequest.deliverResponse(this.mResponse.result),这个就是实现Request抽象类必须要实现的方法,我们来看看StringRequest的源码:

public class StringRequest extends Request<String> {
    private final Listener<String> mListener;

    public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) {
        super(method, url, errorListener);
        this.mListener = listener;
    }

    public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
        this(0, url, listener, errorListener);
    }

    protected void deliverResponse(String response) {
        this.mListener.onResponse(response);
    }

 ...省略
}

在deliverResponse方法中调用了this.mListener.onResponse(response),最终将response回调给了Response.Listener的onResponse()方法。我们用StringRequest请求网络的写法是这样的:

RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());
        StringRequest mStringRequest = new StringRequest(Request.Method.GET, "http://www.baidu.com",
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        Log.i("wangshu", response);
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e("wangshu", error.getMessage(), error);
            }
        });
        //将请求添加在请求队列中
        mQueue.add(mStringRequest);

看到第5行整个Volley的大致流程都通了吧,好了关于Volley的源码就讲到这里。

分享到 评论

Android View体系(九)自定义View

前言

学习了以上的文章后,接下来我们来讲讲自定义View,自定义View一直被认为是高手掌握的技能,因为情况太多,想实现的效果又变化多端,但它也要遵循一定的规则,我们要讲的就是这个规则,至于那些变化多端的酷炫的效果就由各位来慢慢发挥了。但是需要注意的是凡事都要有个度,自定义View毕竟不是规范的控件,如果不设计好不考虑性能反而会适得其反,另外适配起来可能也会产生问题,笔者的建议是如果能用系统控件的还是尽量用系统控件。

查看更多

分享到 评论

Android网络编程(三)Volley用法全解析

100505176ee6982846_副本.jpg
相关文章
Android网络编程系列

前言

Volley想必很多人都用过,为了建立网络编程的知识体系,Volley是必须要讲的知识点,所以我这里有必要再次介绍一下Volley的使用。

查看更多

分享到 评论

Android网络编程(二)HttpClient与HttpURLConnection

java-httpurlconnection-java-http-request_副本.jpg
相关文章
Android网络编程系列

前言

上一篇我们了解了HTTP协议原理,这一篇我们来讲讲Apache的HttpClient和Java的HttpURLConnection,这两种都是我们平常请求网络会用到的。无论我们是自己封装的网络请求类还是第三方的网络请求框架都离不开这两个类库。

查看更多

分享到 评论

Android网络编程(一)HTTP协议原理

http_副本.jpg
相关文章
Android网络编程系列

前言

这篇文章是这个系列的开篇,作为移动开发者,开发的应用不免会对网络进行访问,虽然现在已经有很多的开源库帮助我们可以轻而易举的访问网络,但是我们仍要去了解网络访问的原理,这也是一个优秀开发人员所必备的知识点。这篇文章我们就先来了解一下HTTP协议原理。

查看更多

分享到 评论

Android View体系(八)从源码解析View的layout和draw流程

前言

上一篇文章我们讲了View的measure的流程,接下来我们讲下View的layout和draw流程,如果你理解了View的measure的流程,那这篇文章自然就不在话下了。

查看更多

分享到 评论