初探Android网络请求框架之OkHttp3 | 青训营笔记

206 阅读4分钟

这是我参与「第四届青训营」笔记创作活动的第36天

初探Android网络请求框架之OkHttp3

一、Android 中的网络请求框架有哪些

Android 开发中,网络请求是无法避免的,但也可以不用它。
对于一个需要联网的 APP 来说,网络请求框架就是它的根基。

那网络请求框架有哪些呢?咱们往下看:

  • HttpClient
  • HttpURLConnection
  • OkHttp

以上三个是底层网络请求框架,一般适用于 HTTP 网络协议相关请求的。

往下看,还有封装的网络请求框架:

  • Volley
  • Retrofit
  • Okgo
  • Novate

这三个是基于底层网络请求框架进行的二次框架封装,一般都是用封装版框架。

比如 Volley 内部使用的是 HttpURLConnection 、HttpClient 、OkHttp ,
而 Retrofit 是直接基于 OkHttp 进行的封装,两者进行的封装也大有不同呢。

现在基本已经是 OkHttp + Retrofit 结合使用的天下了,他们的优势也是很明显的,Google 已经再 Android 4.4 之后将 HttpURLConnection 已经替换成了 OkHttp 。

发展史

Android 2.2 之前,HttpClient 是最佳选择,Android 2.2 之后,Google 官方建议使用 HttpURLConnection ,Android 6.0 以后,Google 官方移除了 HttpClient 相关的 API 。

简单对比:

框架OkHttpRetrofitVolleyandroid-async-http
作者square 公司square 公司Google 公司Google 公司
性能拥有Nio和Okio,所以性能更高,请求、处理速度更快。
io:阻塞式,nio:非阻塞式
代码简化,结构彻底,职责细分;易于和RxJava使用,使用方法较多,原理复杂。可拓展性好,可支持HttpClient、HttpURLConnection、OkHttp。Android 5.0 之后已弃用。
场景重量级网络交互场景:网络请求频繁,传输数据量大。---传输数据量小;不能进行大数据的网络操作,比如音频文件的下载传输。---
缺点------致命缺点:不能下载大数据文件。已停止维护。

经过上表的简单对比,能看出来 square 公司开发的 OkHttp ,Retrofit 框架是非常强大的。所以咱们这里说的是 OkHttp3~

二、OkHttp3 长什么样子

  1. 异步 GET 请求:
  • new OkHttpClient();
  • 构造 Request 对象;
  • 通过前两步中的对象构建 Call 对象;
  • 通过 Call#enqueue(Callback) 方法来提交异步请求;
String url = "http://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
    .url(url)
    .get()// 默认就是GET请求,可以不写
    .build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        Log.d(TAG, "onFailure: ");
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        Log.d(TAG, "onResponse: " + response.body().string());
    }
});

异步发起的请求会被加入到 Dispatcher 中的 runningAsyncCalls 双端队列中通过线程池来执行。

  1. 同步 GET 请求:

前面几个步骤和异步方式一样,只是最后一部是通过 Call#execute() 来提交请求,注意这种方式会阻塞调用线程,所以在 Android 中应放在子线程中执行,否则有可能引起 ANR 异常,Android 3.0 以后已经不允许在主线程访问网络。

String url = "http://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
    .url(url)
    .build();
Call call = okHttpClient.newCall(request);
new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            Response response = call.execute();
            Log.d(TAG, "run: " + response.body().string());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}).start();
  1. POST 方式提交 String

这种方式与前面的区别就是在构造 Request 对象时,需要多构造一个 RequestBody 对象,用它来携带我们要提交的数据。在构造 RequestBody 需要指定 MediaType ,用于描述请求 / 响应 body 的内容类型,关于 MediaType 的更多信息可以查看 RFC 2045RequstBody 的几种构造方式:

img1

MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8");
String requestBody = "I am Purpleaf.";
Request request = new Request.Builder()
        .url("https://api.github.com/markdown/raw")
        .post(RequestBody.create(mediaType, requestBody))
        .build();
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        Log.d(TAG, "onFailure: " + e.getMessage());
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        Log.d(TAG, response.protocol() + " " + response.code() + " " + response.message());
        Headers headers = response.headers();
        for (int i = 0; i < headers.size(); i++) {
            Log.d(TAG, headers.name(i) + ":" + headers.value(i));
        }
        Log.d(TAG, "onResponse: " + response.body().string());
    }
});

我们大致看了看 OkHttp3 长什么样子,GET 的和 POST 的。

三、看一看 OkHttp3 整体流程

img2

  1. OkHttpClient 实现 Call.Factory ,负责为 Request 创建 Call
  2. RealCall 为具体的 Call 实现,其 enqueue() 异步接口通过 Dispatcher 利用 ExecutorService 实现,而最终进行网络请求时和同步 execute() 接口一致,都是通过 RealCall 中的 getResponseWithInterceptorChain() 函数实现。
  3. getResponseWithInterceptorChain() 中利用 Interceptor 链条,分层实现缓存、透明压缩、网络 IO 等功能。

大概看一看即可,我们今天是来初探 OkHttp3 哒~ 别忘了哦!

四、总结

我们大致上预览了一遍,也简单对比了一下其他网络请求框架。可以看到 OkHttp3 的代码是比较简单的,多数为链式调用,对于开发者非常友好,但是内部封装逻辑过为复杂。然后通过上边的图片也大致过了一下它的整体过程,虽然现在一时半会儿看不懂,但是随着时光流逝,自身技术的提高,就会懂啦~

今天是青训营最后一天,祝同学们学习进步,马到成功哈!