之前的文章从理论上介绍了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  Callback.Cancelable post(RequestParams entity, Callback.CommonCallback callback) {        return request(HttpMethod.POST, entity, callback);    }    @Override    public  Callback.Cancelable request(HttpMethod method, RequestParams entity, Callback.CommonCallback callback) {        entity.setMethod(method);        Callback.Cancelable cancelable = null;        if (callback instanceof Callback.Cancelable) {            cancelable = (Callback.Cancelable) callback;        }        HttpTask task = new HttpTask(entity, cancelable, callback);        return x.task().start(task);    }

    public HttpTask(RequestParams params, Callback.Cancelable cancelHandler,                    Callback.CommonCallback 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(), 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. Android(安卓)的网络编程(17)-android显示网络图片
  2. android中线程的应用
  3. android消息机制
  4. Android进程与线程基本知识
  5. 浅析Android单线程模型
  6. Android(安卓)多线程之几个基本问题
  7. Android异步处理三:Handler+Looper+MessageQueue深入详解
  8. Android(安卓)性能优化的一些方法
  9. 【Android】性能优化的一些方法

随机推荐

  1. android常用颜色
  2. Android的Activity启动流程分析
  3. android 的button
  4. TextView跑马灯效果
  5. android Activity
  6. Android
  7. Android(安卓)shell命令大全
  8. android listview去掉分割线
  9. android读取文件权限
  10. Android(安卓)TextView布局__2019.09.02