Android OkHttp源码阅读详解一

博主前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住也分享一下给大家

👉点击跳转到教程

前言:源码阅读基于okhttp:3.10.0

Android中OkHttp源码阅读二(责任链模式)

c 复制代码
implementation 'com.squareup.okhttp3:okhttp:3.10.0'

1、首先回顾OkHttp的使用

c 复制代码
public class MainActivity extends RxActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    /**
     * OkHttp的使用
     */
    private static void okHttpUseAction() {
        //通过构建者设计模式得到OkHttpClient
        OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
        //get请求 构建者模式拿到request
        Request request = new Request.Builder().url("https://www.baidu.com/").get().build();
        //Call  call = RealCall
        Call call = okHttpClient.newCall(request);
//        call.cancel();//取消请求
        //同步方法,我们需要自己开启子线程 耗时
//        try {
//            Response response = call.execute();
//            String string = response.body().string();
//            InputStream inputStream = response.body().byteStream();
//            Reader reader = response.body().charStream();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }

        //异步方法
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                System.out.println("请求失败...");
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String string = response.body().string();
                System.out.println("请求完成:" + string);
//                InputStream inputStream = response.body().byteStream();
//                Reader reader = response.body().charStream();
            }
        });
    }

    public static void main(String[] args) {
        okHttpUseAction();
    }
}

2、OkHttp源码阅读之线程池详解

c 复制代码
/**
 * @Author: ly
 * @Date: 2023/9/3
 * @Description: 线程池的使用
 */
public class MyThreadPool {
    public static void main(String[] args) {
        //比较耗性能,开启子线程,然后回收
        new Thread() {
            @Override
            public void run() {
                super.run();
            }
        }.start();
        //java 1.5 线程如何复用  线程池复用
        //子线程
        //需要一份工作:招聘工作,员工完成工作后,解聘
        //需要一份工作:招聘工作,员工完成工作后,解聘
        //需要一份工作:招聘工作,员工完成工作后,解聘

        //线程池相当于以下
        //需要一份工作:招聘工作,员工完成工作后,继续执行其他工作,解雇

        //java 1.5 线程池复用,线程池(线程,如何让这么多线程复用,线程管理工作)
        //Executor
        //    --ExecutorService
        //        --AbstractExecutorService
        //          --ThreadPoolExecutor
        //ThreadPoolExecutor 学习此类

        //线程池里面,只有一个核心线程在跑任务
        /**
         * corePoolSize:核心线程数
         * maximumPoolSize:线程池非核心线程数,线程池规定大小
         * keepAliveTime:时间数值
         * unit:时间单位
         *       参数三和四作用:正在执行的任务Runnable 20 大于核心线程数  参数三和参数四才会起作用
         *       作用:Runnable1执行完毕后闲置60s,如果过了闲置60s,会回收掉Runnable1,如果在闲置时间60s内,复用此线程Runnable1
         * workQueue:队列
         *            作用:会把超出的任务加入到队列中,缓存起来
         */
//        ExecutorService executorService = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>());

        //Exception in thread "main" java.lang.IllegalArgumentException  会崩溃
//        ExecutorService executorService = new ThreadPoolExecutor(5,
//                1, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>());

//        ExecutorService executorService = new ThreadPoolExecutor(5,
//                10, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>());

        //想实现缓存,线程池方案
        /**
         * corePoolSize:核心线程数
         * maximumPoolSize:最大线程数。线程池非核心线程数,线程池规定大小
         * keepAliveTime:时间数值
         * unit:时间单位
         *       参数三和四作用:正在执行的任务Runnable 20 大于核心线程数  参数三和参数四才会起作用
         *       作用:Runnable1执行完毕后闲置60s,如果过了闲置60s,会回收掉Runnable1,如果在闲置时间60s内,复用此线程Runnable1
         * workQueue:队列
         *            作用:会把超出的任务加入到队列中,缓存起来
         */
//        ExecutorService executorService = new ThreadPoolExecutor(0,
//                Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>());

        ExecutorService executorService = new ThreadPoolExecutor(0,
                Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new SynchronousQueue<>(),
                new ThreadFactory() {
                    @Override
                    public Thread newThread(Runnable r) {
                        Thread thread = new Thread();
                        thread.setName("MyOkHttp Dispatcher");
                        thread.setDaemon(false);//不是守护线程
                        return thread;
                    }
                });

        for (int i = 0; i < 20; i++) { //循环第二次,闲置60s,复用上一次任务
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);
                        System.out.println("当前线程,执行耗时任务,线程是:" + Thread.currentThread().getName());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }


        /**************************************JAVA提供了API***********************************************/

        //Java设计者考虑到了不用使用线程池的参数配置,提供了API
        ExecutorService executorService1 = Executors.newCachedThreadPool();
        executorService1.execute(new Runnable() {
            @Override
            public void run() {

            }
        });

        //线程池里面只有一个核心线程,最大线程也只有一个
        ExecutorService executorService2 = Executors.newSingleThreadExecutor();

        Executors.newFixedThreadPool(5); //指定固定大小线程池
    }
}

3、守护线程详解

c 复制代码
/**
 * @Author: ly
 * @Date: 2023/9/3
 * @Description: 守护线程的使用
 */
public class MyThread {
    public static void main(String[] args) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                super.run();
                while (true) {
//                    try {
//                        Thread.sleep(10);
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                    } finally {
//                        System.out.println("run...");
//                    }
                    System.out.println("run...");
                }
            }
        };
        //守护线程
        thread.setDaemon(true);
        thread.start();
        //JVM main()所持有的进程该结束了
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

4、根据OkHttp中构建者模式写一个例子

1.定义一个类HomeParam

c 复制代码
/**
 * @Author: ly
 * @Date: 2023/9/3
 * @Description: 房子的图纸
 */
public class HomeParam {
    private double width;
    private double height;
    private String color = "白色";

    public HomeParam() {
    }

    public HomeParam(double width, double height, String color) {
        this.width = width;
        this.height = height;
        this.color = color;
    }

    public double getWidth() {
        return width;
    }

    public void setWidth(double width) {
        this.width = width;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "画出来的图纸:HomeParam{" +
                "width=" + width +
                ", height=" + height +
                ", color='" + color + '\'' +
                '}';
    }
}

2.定义一个类House

c 复制代码
/**
 * @Author: ly
 * @Date: 2023/9/3
 * @Description: 真实存在的房子
 */
public class House {
    private double width;
    private double height;
    private String color;

    public House() {
    }

    public House(double width, double height, String color) {
        this.width = width;
        this.height = height;
        this.color = color;
    }

    public double getWidth() {
        return width;
    }

    public void setWidth(double width) {
        this.width = width;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "具体建造出来的房子:House{" +
                "width=" + width +
                ", height=" + height +
                ", color='" + color + '\'' +
                '}';
    }
}

3、定义一个类Worker

c 复制代码
/**
 * @Author: ly
 * @Date: 2023/9/3
 * @Description: 工人开始建造房子
 */
public class Worker {
    //拿到图纸
    private HomeParam mHomeParam;

    public void setHomeParam(HomeParam homeParam) {
        mHomeParam = homeParam;
    }

    //工作,盖房子
    public House buildHouse() {
        House house = new House();
        house.setHeight(mHomeParam.getHeight());
        house.setWidth(mHomeParam.getWidth());
        house.setColor(mHomeParam.getColor());
        return house;
    }
}

4、定义一个类DesignerPerson

c 复制代码
/**
 * @Author: ly
 * @Date: 2023/9/3
 * @Description: 设计师
 */
public class DesignerPerson {
    private HomeParam mHomeParam;
    private Worker mWorker;

    public DesignerPerson() {
        mHomeParam = new HomeParam();
        mWorker = new Worker();
    }

    /**
     * 增加楼层
     *
     * @param height 高度
     */
    public DesignerPerson addHeight(double height) {
        mHomeParam.setHeight(height);
        return this;
    }

    /**
     * 增加宽度
     *
     * @param width 宽度
     */
    public DesignerPerson addWidth(double width) {
        mHomeParam.setWidth(width);
        return this;
    }

    /**
     * 增加颜色
     *
     * @param color 颜色
     */
    public DesignerPerson addColor(String color) {
        mHomeParam.setColor(color);
        return this;
    }

    /**
     * 把图纸给工人
     * 员工说房子盖好了
     *
     * @return
     */
    public House build() {
        mWorker.setHomeParam(mHomeParam);
        return mWorker.buildHouse();
    }
}

5.定义一个类UserClient

c 复制代码
/**
 * @Author: ly
 * @Date: 2023/9/3
 * @Description: 用户有一个需求盖房子
 */
public class UserClient {
//    public static void main(String[] args) {
    //第一版

    //找到建筑公司
//        DesignerPerson designerPerson = new DesignerPerson();
//        designerPerson.addHeight(4);
//        designerPerson.addWidth(120.0);
//        designerPerson.addColor("绿色");
//
//        designerPerson.addHeight(2);
//        designerPerson.addWidth(100.0);
//        designerPerson.addColor("红色");
//
//        designerPerson.addHeight(3);
//        designerPerson.addWidth(90.0);
//        designerPerson.addColor("黄色");
//
//        //复制的过程
//
//        House house = designerPerson.build();
//        System.out.println(house);
//    }

    public static void main(String[] args) {
        //第二版,链式调用
        House house = new DesignerPerson().addColor("白色")
                .addWidth(100)
                .addHeight(8)
                .build();
        System.out.println(house);
    }
}

2、OkHttp主线流程源码阅读

c 复制代码
1.OSI七层模型,TCP/IP模型(四层),HTTP格式
  OSI七层参考模型  --> TCP/IP参考模型
  TCP/IP参考模型四层:
  应用层 --> HTTP,HTTPS
  传输层 --> Socket

  HTTP get(请求行,请求属性集) post(请求行,请求属性集,type(form表单提交,还是其他提交),len(长度)==请求体)

2.OkHttp源码的主线流程
OkHttp的使用

OkHttpClient 通过构建者设计模式得到OkHttpClient
Request  通过构建者设计模式得到Request
Call  实际得到的是final class RealCall implements Call
//异步方法
call.enqueue(new Callback()
//不能执行大于1次 enqueue 否则会抛出异常Exception in thread "main" java.lang.IllegalStateException: Already Executed
synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
//拿到调度器dispatcher执行enqueue()方法
client.dispatcher().enqueue(new AsyncCall(responseCallback));

Dispatcher{
 /** Ready async calls in the order they'll be run. */  等待队列
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

   运行的队列
  /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

  //最终会调用到Dispatcher类中的enqueue()方法
  synchronized void enqueue(AsyncCall call) {
      //同时运行的异步任务小于64&&同时访问(同一个)的服务器,不能超过5个  条件满足加入到运行队列中,然后执行
      if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
        runningAsyncCalls.add(call);
        executorService().execute(call); //执行
      } else {
        //加入到等待队列
        readyAsyncCalls.add(call);
      }
    }

  Deque双端队列:Deque(双端队列)是一种用于管理HTTP请求和响应拦截器的数据结构。
                Deque是"Double-ended Queue"的缩写,表示它可以在两端进行元素的插入和删除操作。

  AsyncCall 执行耗时任务
           signalledCallback 为true:这个错误是用户造成的,和OkHttp没有关系
                             为false:这个错误是OkHttp造成的。 onFailure

}

梳理主线流程:
OkHttpClient --> Request -> newCall  RealCall.enqueue(){不能重复执行} --> Dispatcher.enqueue(AsyncCall)-->
Dispatcher{if:先加入运行队列里面去,执行异步任务 else 直接加入等待队列} --> 异步任务 AsyncCall.execute()

分析OkHttp里面的线程池
executorService().execute(call);

public synchronized ExecutorService executorService() {
    if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
}
分析结果:OkHttp里面的线程池,采用的是缓存方案+线程工厂 name  不是守护线程
总结:采用的是缓存方案+定义线程工程(设置线程名,设置不是守护线程)
缓存方案:参数1 == 0
         参数2 == Integer.MAX_VALUE
         参数3 == 60s闲置时间,只要Runnable > 大于参数1  起作用(60s 之内就会复用之前的任务,60s之内就会回收任务)

--------------------------------->
看OkHttp源码,发现OkHttp里面使用了构建者设计模式,所以才要学习构建者设计模式
OkHttpClient ---构建者模式
Request      ---构建者模式
开始学习构建者设计模式 -->盖房子的例子(根据OkHttp源码中的链式调用优化)
相关推荐
每次的天空33 分钟前
Kotlin 内联函数深度解析:从源码到实践优化
android·开发语言·kotlin
练习本1 小时前
Android MVC架构的现代化改造:构建清晰单向数据流
android·架构·mvc
早上好啊! 树哥1 小时前
android studio开发:设置屏幕朝向为竖屏,强制应用的包体始终以竖屏(纵向)展示
android·ide·android studio
YY_pdd2 小时前
使用go开发安卓程序
android·golang
Android 小码峰啊4 小时前
Android Compose 框架物理动画之捕捉动画深入剖析(29)
android·spring
bubiyoushang8884 小时前
深入探索Laravel框架中的Blade模板引擎
android·android studio·laravel
cyy2984 小时前
android 记录应用内存
android·linux·运维
CYRUS STUDIO4 小时前
adb 实用命令汇总
android·adb·命令模式·工具
这儿有一堆花5 小时前
安卓应用卡顿、性能低下的背后原因
android·安卓
byte轻骑兵5 小时前
【Bluedroid】蓝牙HID DEVICE断开连接流程源码分析
android·c++·蓝牙·hid·bluedroid