Android高性能编码实战:网络框架优化
之前的文章从理论上介绍了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,替换它能够优化网络调用的性能,并且会有较低的内存。
更多相关文章
- Android进程与线程基本知识
- 浅析Android单线程模型
- Android 多线程之几个基本问题
- Android热修复(2):AndFix热修复框架的使用
- Android/java 多线程(六)-AsyncTask使用详解及源码分析
- Android AAC框架从入门到精通
- Android HttpURLConnection网络通信
- 腾讯开源的Android UI框架——QMUI Android
- android 获取网络类型名称2G 3G 4G wifi