OkOne-基于okhttp的网络性能优化框架

3,956 阅读4分钟

简介

OkOne是一款基于okhttp库的网络性能优化框架,但不同于其他框架对okhttp的使用调用进行封装,而是从不一样的方面,以对开发者无侵入的方式进行优化。

痛点

在APP项目中可能会包含多个组件模块,或依赖多个三方库,甚至部门分不同团队开发各自业务模块AAR供APP集成。其中可能都有使用到okhttp框架进行网络请求,不同的组件模块和三方库中各自创建OkHttpClient实例,或有开发者未通过单例缓存OkHttpClient,而是每次请求每次新建。这样将造成极大浪费,并且导致不能充分利用okhttp的请求队列和连接池等控制和优化措施

解决

借助该OkOne库可以无侵入地将分散在不同组件中的OkHttpClient进行收敛,由OkOne进行统一管理和复用。OkOne会比较OkHttpClient.Builder进行区分复用,即相同配置的OkHttpClient.Builder将自动复用同一个OkHttpClient实例。

集成

集成很简单,仅需三步:

Minimum supported Gradle version is 6.5

  • 1.在项目根目录的build.gradle里添加依赖
dependencies {
    classpath 'com.cdh.okone:gradle:0.1.0'
}
  • 2.在app module的build.gradle里应用插件
apply plugin: 'plugin.cdh.okone'
  • 3.在app module的build.gradle的dependencies里添加依赖
implementation 'com.cdh.okone:okone:0.1.2'

至此已完成接入,运行即会自动生效。

效果

现在来看看实际效果,在demo中创建三个不同配置的OkHttpClient.Builder:

// builder1
OkHttpClient.Builder builder1 = new OkHttpClient.Builder()
    .connectTimeout(10, TimeUnit.SECONDS)
    .addInterceptor(new HttpLoggingInterceptor())
    .eventListener(mEventListener);
    
// builder2
OkHttpClient.Builder builder2 = new OkHttpClient.Builder()
    .retryOnConnectionFailure(true)
    .minWebSocketMessageToCompress(2048)
    .eventListener(mEventListener);
    testRequestServer(builder2);

// builder3
OkHttpClient.Builder builder3 = new OkHttpClient.Builder()
    .connectTimeout(10, TimeUnit.SECONDS)
    .addInterceptor(new HttpLoggingInterceptor())
    .retryOnConnectionFailure(true)
    .minWebSocketMessageToCompress(2048)
    .eventListener(mEventListener);

实例复用

接下来分别用这三个Builder构建OkHttpClient进行请求:

    private void testRequestServer(OkHttpClient.Builder builder) {
        // 这里不缓存client,每次都build
        OkHttpClient client = builder.build();
        // 打印日志
        Log.d(TAG, "创建OkHttpClient: " + client);

        Request request = new Request.Builder()
                .url(api)
                .build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {}

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {}
        });
    }

可以看到这里每次都build一个OkHttpClient来进行请求。

现在按照下面的顺序来调用:

// 先使用builder1请求两次
testRequestServer(newBuilder1());
testRequestServer(newBuilder1());
// 换成builder2请求两次
testRequestServer(newBuilder2());
testRequestServer(newBuilder2());
// 再换成builder3请求两次
testRequestServer(newBuilder3());
testRequestServer(newBuilder3());

接着来看看打印日志: okone复用

可以看到OkOne成功对OkHttpClient实例进行了复用,虽然每次请求都build来获得OkHttpClient,但不会实际产生多个实例。并且不同配置的Builder不会互相影响,通过builder1、builder2、builder3构建分别复用各自的OkHttpClient。如果未集成OkOne,那么将会产生6个OkHttpClient实例。

连接复用

继续看连接是否成功复用,通过EventListener添加日志来查看:

private EventListener mEventListener = new EventListener() {
    // 在每个重写方法中添加Log打印日志 
    // 限于篇幅省略代码···
}

通过OkHttpClient.Builder#eventListener设置自定义EventListener。

接下来仍然按照Builder1、Builder1、Builder2、Builder2、Builder3、Builder3的顺序请求,查看日志。

  • Builder1第一次请求 okone1 可以看到当前还没有可复用连接,请求经历了dns和握手建联过程。

  • Builder1第二次请求 okone2 此次请求有复用连接,免去了dns和握手建联的过程。若未集成OkOne,则还会经历一次完整的建联过程。

  • Builder2第一次请求 okone3 builder2和builder1配置不同,不复用builder1的OkHttpClient,因此走完整请求过程。

  • Builder2第二次请求 okone4 此时请求也不用再dns和握手建联。

  • Builder3第一次请求 okone5 新建OkHttpClient,无复用连接。

  • Builder3第二次请求 okone6 成功复用。

可以看到有效利用了okhttp的连接池,避免每次请求都重新走dns和握手建联过程。若未集成OkOne库则每次都走完整请求过程。

更多功能

关闭开关

是否启用或关闭OkHttpClient统一复用和管理,需要在创建OkHttpClient前设置。

// true启用,false关闭。默认true。
OkOne.useGlobalClient = true;

打印日志

打开或关闭OkOne打印日志。

// true打印,false不打印。默认true。
OkOne.setLogEnable(true);

单独创建不受控的OkHttpClient实例

单独创建一个不经OkOne管理和复用的OkHttpClient。

OkHttpClient client = new OkHttpClient(builder)

GitHub地址

github.com/chidehang/O…