一、浅谈启动性能优化原因
1、引起性能问题的原因
随着项目不断的快速迭代,往往会造成App启动卡慢现象,因为可能在App主进程启动阶段或者在主界面启动阶段放了很多初始化其他业务的逻辑,而这些业务落地可能一开始并不需要用到;
2、为什么要做启动速度优化
- App启动卡慢会影响一个App的卸载率和使用率;
- 启动速度快会给人一种轻快的感觉,减少用户等待时间;
- 如果一个App从点击桌面图标到看到主界面花了10秒,请问你能接受么?忍耐不好的估计直接就卸载了,或者没等打开就直接Home键按出去,然后杀进程了;这样一来App卸载率提升了,使用率下降了。所以对于有大量用户的App来说,这些性能细节是很重要的;
二、分析怎么做启动优化
1、启动过程简单分析
App从点击桌面图标到我们看到App的主界面整个过程中经过了哪些步骤,哪些地方是我们可以优化的地方;
下图是App启动过程的一个大概描述
2、从启动过程找出优化点
App启动过程中我们优化的地方包括主进程启动流程和主界面启动流程,主进程启动就是Application的创建过程,主界面启动就是MainActivity的创建过程;
只需要分别对这两个部分进行优化即可:
- Application中attachBaseContext最早被调用,随后是onCreate方法,尽量在这两个方法中不要有耗时操作;
- MainActivity中重点关注onCreate,onResume,onWindowFocusChange;
3、统计耗时操作
函数耗时统计工具之Hugo
Hugo项目是一个调试函数调用耗时的工具,通过对方法或者类添加@DebugLog注解,在运行时会将函数的耗时打印在控制台中,通常用于排查函数耗时,或者用于卡顿检测;
①使用方法
项目根目录build.gradle添加hugo插件依赖
- classpath 'com.jakewharton.hugo:hugo-plugin:1.2.1'
②主工程或者library的录build.gradle中声明hugo插件
- apply plugin: 'com.jakewharton.hugo'
复制代码可通过配置开启或关闭hugo功能。
- hugo {
- enabled false
- }
③在类或方法上声明@DebugLog注解
- @DebugLog
- public String getName(String first, String last) {
- SystemClock.sleep(15);
- return first + " " + last;
- }
④运行程序会在控制台会打印函数耗时日志:
- getName [16ms] = "testtest"
其实 hugo项目很简单,后续我们会讲解怎么自己写一个;
三、优化步骤
1、Application中加入异步线程
是把不必要提前做的操作放到异步线程中去做,也就是我们经常做的异步加载;
下面简单写个代码示例
- public class StartUpApplication extends Application {
- @Override
- public void onCreate() {
- // 程序创建时调用,次方法应该执行应该尽量快,否则会拖慢整个app的启动速度
- super.onCreate();
- onSyncLoadForCreate();
- }
- @Override
- protected void attachBaseContext(Context base) {
- super.attachBaseContext(base);
- onSyncLoad();
- onAsyncLoad();
- }
- private void onSyncLoadForCreate() {
- Logutils.log("onSyncLoadForCreate ");
- Thread.sleep(200);模拟阻塞200毫秒
- }
- private void onSyncLoad() {
- Logutils.log("onSyncLoad ");
- Thread.sleep(200);模拟阻塞100毫秒
- }
- public void onAsyncLoad() {
- new Thread(new Runnable() {
- @Override
- public void run() {
- // 异步加载逻辑
- }
- }, "ApplicationAsyncLoad").start();
- }
- }
2、主页面加入异步线程和延迟加载功能
与Application的优化思路一样,也是封装onSyncLoad和onAsyncLoad方法对现有代码进行一个分类,但是这两个方法的调用时机要晚一点,是在主界面首屏绘制完成的时候调用。这个步骤也需要new一个Thead,属于额外的开销,不过这不影响我们整体性能;
3、态加载布局:主布局文件优化
把主界面中不需要第一次就用到的布局全部使用动态加载的方式来处理,使用ViewStub或者直接在使用时动态addView的方式;
4、主布局文件深度优化
如果做了上面这些优化还是会发现进入主界面还是有些慢,那么需要重点关注主布局文件了。主布局文件的复杂度直接影响到了Activity的加载速度,这个时候需要对主布局文件进行深度优化了;
Activity在加载布局的时候,会对整个布局文件进行解析,测量(measure),布局(layout)和绘制(draw),所以设计简单合理的布局尤为重要。几个重要的优化如下:
- 减少布局层级
- 减少首次加载View的数量
- 减少过度绘制
5、页面功能的分模块化和懒加载
- 一个页面上有很多功能模块,最好每个功能模块都单独的分开,模块之间用接口进行数据沟通;
- 按需加载所需要的功能,不要打开一个页面都加载所有的功能;
- 加载完所需要的功能,如果是一次性加载不需要保持在内存中,尽快销毁掉,形成良好的习惯;
总结:
优化是一条持续之路,通过优化我们可以了解到影响启动性能的因素有哪些,这样我们平时在编码的过程中就会多注意自己的代码性能;
其实优化还有很多办法,比如资源文件的优化、耗性能的写在c++层、合理的设计模式等等,我们做的就是规范我们的代码,让我们自己变的更强大更好。