Android高性能编码实战:网络框架优化

来源:互联网 发布:剪切歌曲软件 编辑:程序博客网 时间:2024/06/06 00:52

之前的文章从理论上介绍了Android高性能编码的几个优化的方向,下面我们从实战的角度讲述如何优化

Android高性能编码实战:App启动优化

Android高性能编码实战:网络框架优化

Android高性能编码实战:修复内存泄漏

之前的App启动优化最后提到了网络框架的优化问题,本篇将针对这个问题对APP进一步优化

04-26 18:14:59.504 11295-11295/com.js.test E/xutils: app start at 149320169950304-26 18:14:59.845 11295-11295/com.js.test E/xutils: Launch app cost time 34204-26 18:14:59.845 11295-11295/com.js.test E/xutils: Enter appFragment cost time 34204-26 18:15:00.088 11295-11295/com.js.test E/xutils: Call first api cost time 585

之前优化过后第一次网络调用的结果

I/ActivityManager: Displayed com.js.test/.ui.activity.MainActivity: +618ms (total +1s296ms)I/ActivityManager: Displayed com.js.test/.ui.activity.MainActivity: +403ms (total +1s18ms)I/ActivityManager: Displayed com.js.test/.ui.activity.MainActivity: +411ms (total +1s38ms)I/ActivityManager: Displayed com.js.test/.ui.activity.MainActivity: +415ms (total +1s31ms)I/ActivityManager: Displayed com.js.test/.ui.activity.MainActivity: +417ms (total +1s47ms)I/ActivityManager: Displayed com.js.test/.ui.activity.MainActivity: +415ms (total +1s45ms)

冷启动APP到完全展示的耗时

Xutls,作为一个快速开发的框架,Xutils集成了网络调用、数据库、图片处理和View注入等常用的模块,解决了快速开发的难点,基本上开发人员使用封装过的xutil之后,就只剩下界面和业务逻辑了,非常方便。好了,言归正传,我们先对比一下使用Xutils3 和Retrofit + OkHttp3的网络框架处理网络请求的TraceView。


XUtils的TraceView消耗389.371毫秒,占CPU时间25.6%

主要的性能消耗是线程池的创建和一次网络请求


占用内存38.47MB

04-26 18:18:16.197 17131-17131/com.js.test E/retrofit: app start at 149320189619604-26 18:18:16.535 17131-17131/com.js.test E/retrofit: Launch app cost time 33904-26 18:18:16.535 17131-17131/com.js.test E/retrofit: Enter appFragment cost time 33904-26 18:18:16.770 17131-17131/com.js.test E/retrofit: Call first api cost time 574

采用retrofit2+okhttp3 启动APP到第一次网络调用耗时(两种方式均采用fastJson进行json解析)

I/ActivityManager: Displayed com.js.test/.ui.activity.MainActivity: +469ms (total +1s165ms)I/ActivityManager: Displayed com.js.test/.ui.activity.MainActivity: +389ms (total +1s12ms)I/ActivityManager: Displayed com.js.test/.ui.activity.MainActivity: +379ms (total +1s6ms)I/ActivityManager: Displayed com.js.test/.ui.activity.MainActivity: +381ms (total +1s10ms)I/ActivityManager: Displayed com.js.test/.ui.activity.MainActivity: +370ms (total +992ms)I/ActivityManager: Displayed com.js.test/.ui.activity.MainActivity: +372ms (total +996ms)I/ActivityManager: Displayed com.js.test/.ui.activity.MainActivity: +377ms (total +1s2ms)I/ActivityManager: Displayed com.js.test/.ui.activity.MainActivity: +391ms (total +1s12ms)

冷启动APP耗时


采用retrofit2+okhttp3 进行第一次网络调用,启动到请求完成共耗时574毫秒,接口返回速度上没有太大差别,冷启动时间表现比xutils好,

内存占用小于xutils,使用Xutils的内存比retrofit2+okhttp3 要大将近4MB,这个还是蛮大的,对于移动设备来说。xutils其他部分在本例中并没有使用,可以忽略。


采用retrofit2+okhttp3的框架的TraceView,我们看到线程池占用的cpu时间是比较小额,下面我们从线程池的角度分析比较两种框架

    @Override    public <T> Callback.Cancelable post(RequestParams entity, Callback.CommonCallback<T> callback) {        return request(HttpMethod.POST, entity, callback);    }    @Override    public <T> Callback.Cancelable request(HttpMethod method, RequestParams entity, Callback.CommonCallback<T> callback) {        entity.setMethod(method);        Callback.Cancelable cancelable = null;        if (callback instanceof Callback.Cancelable) {            cancelable = (Callback.Cancelable) callback;        }        HttpTask<T> task = new HttpTask<T>(entity, cancelable, callback);        return x.task().start(task);    }

    public HttpTask(RequestParams params, Callback.Cancelable cancelHandler,                    Callback.CommonCallback<ResultType> callback) {        super(cancelHandler);......        // init executor        if (params.getExecutor() != null) {            this.executor = params.getExecutor();        } else {            if (cacheCallback != null) {                this.executor = CACHE_EXECUTOR;            } else {                this.executor = HTTP_EXECUTOR;            }        }    }

进行第一次请求时,创建HttpTask,引用线程池

    private static final PriorityExecutor HTTP_EXECUTOR = new PriorityExecutor(5, true);    private static final PriorityExecutor CACHE_EXECUTOR = new PriorityExecutor(5, true);

Xutils的线程池是HttpTask静态成员变量,类加载时自动创建,线程池corePoolSize是5,居然创建了两个线程池。

  /** Executes calls. Created lazily. */  private ExecutorService executorService;

okhttp3 在Dispatcher里面的线程池是使用时才创建的

  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;  }

并且,线程池创建时corePoolSize的大小为0

    public void execute(Runnable command) {        if (command == null)            throw new NullPointerException();        /*         * Proceed in 3 steps:         *         * 1. If fewer than corePoolSize threads are running, try to         * start a new thread with the given command as its first         * task.  The call to addWorker atomically checks runState and         * workerCount, and so prevents false alarms that would add         * threads when it shouldn't, by returning false.         *         * 2. If a task can be successfully queued, then we still need         * to double-check whether we should have added a thread         * (because existing ones died since last checking) or that         * the pool shut down since entry into this method. So we         * recheck state and if necessary roll back the enqueuing if         * stopped, or start a new thread if there are none.         *         * 3. If we cannot queue task, then we try to add a new         * thread.  If it fails, we know we are shut down or saturated         * and so reject the task.         */        int c = ctl.get();        if (workerCountOf(c) < corePoolSize) {            if (addWorker(command, true))                return;            c = ctl.get();        }        if (isRunning(c) && workQueue.offer(command)) {            int recheck = ctl.get();            if (! isRunning(recheck) && remove(command))                reject(command);            else if (workerCountOf(recheck) == 0)                addWorker(null, false);        }        else if (!addWorker(command, false))            reject(command);    }

线程池 execute,先判断线程池的corePoolSize是否足够,不够double check之后,创建新的worker add进来。

xutils由于创建了多余的线程池,而且线程数量多,异步占用的cpu时间是比较高的,这个增加冷启动的时间,也消耗了很多内存。

进过分析,xutils框架在网络调用方面表现不如retrofit2+okhttp3,替换它能够优化网络调用的性能,并且会有较低的内存。



1 0
原创粉丝点击