Skip to content

Latest commit

 

History

History
356 lines (243 loc) · 8.52 KB

3.App启动优化.md

File metadata and controls

356 lines (243 loc) · 8.52 KB

3-2 App启动优化介绍

  1. 背景介绍

    1. 启动是第一体验
    2. 八秒定律
  2. 启动分类

    1. App startup time

      1. 冷启动

        耗时最多,衡量标准

        需要了解冷启动流程

      2. 热启动

        最快

      3. 温启动

        较快

  3. 相关任务

    1. 冷启动之前
      1. 启动App
      2. 加载空白Window
      3. 创建进程
    2. 随后任务
      1. 创建Application
      2. 启动主线程
      3. 创建MainActivity
      4. 加载布局
      5. 布置屏幕
      6. 首帧绘制
  4. 优化方向

    Application和Activity生命周期

3-3 启动时间测量方式

  1. adb命令

    adb shell am start -W packagename/packagename.首屏Activity
    eg:adb shell am start -W com.iyueke.kids/com.iyueke.kids.ui.detail.splash.SplashActivity

    ThisTime:最后一个Activity启动耗时

    TotalTime:所有Activity启动耗时

    WaitTime:AMS启动Activity的总耗时

    线下使用方便,不能带到线上,可以参照竞品

    非严谨、精确时间

  2. 手动打点

    启动时埋点,启动结束埋点,二者差值

    LaunchTimer类辅助打点

    开始时间:Application#attachBaseContext

    结束时间误区:Activity#onWindowFocusChanged只是首帧时间

    结束时间正解:真实数据展示,数据第一条展示

    精确,可带到线上,推荐使用

    避开误区,采用数据第一条展示

3-4 启动优化工具选择

  1. traceview

    图形的形式展示执行时间、调用栈等

    信息全面,包含所有线程

    使用方式:

    1. Debug.startMethodTracing("App")
    2. Debug.stopMethodTracing("")
    3. 生成文件在sd卡:Android/data/packagename/files
    4. 在Android Studio中打开生成文件

    运行时开销严重,整体都会变慢

    可能会带偏优化方向

    traceview和cpu profiler

  2. systrace

    结合Android内核的数据,生成Html报告

    API 18以上使用,推荐TraceCompat

    使用方式:

    1. TraceCompat.beginSection("ApponCreate")
    2. TraceCompat.endSection()
    3. 运行python脚本:python systrace.py -t 10 [other-options][categories]

    轻量级,开销小

    直观反映cpu利用率

    cputime和walltime区别

    1. cputime是代码消耗cpu的时间(重点指标)
    2. walltime是代码执行时间
    3. cputime为什么和walltime不一样,举例:锁冲突

3-6 优雅获取方法耗时讲解

  1. 常规方式

    背景:需要知道启动阶段所有方法耗时

    实现:手动埋点

    1. long time = System.currentTimeMillis()
    2. long cost= System.currentTimeMillis() - time
    3. 或者SystemClock.currentThreadTimeMillis()

    侵入性强、工作量大

  2. AOP介绍

    Aspect Oriented Programming,面向切面编程

    1. 针对同一类问题的统一处理
    2. 无侵入添加代码

    AspectJ使用

    1. classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.0'
    2. implementation 'org.aspectj:aspectjrt:1.8.+'
    3. apply plugin: 'android-aspectjx'

    Join Points:程序运行时的执行点,可以作为切面的地方

    1. 函数调用、执行
    2. 获取、设置变量
    3. 类初始化

    PointCut:带条件的Join Points

    Advice:一种Hook,要插入代码的位置

    1. Before:PointCut之前执行
    2. After:PointCut之后执行
    3. Around:PointCut之前、之后分别执行

    语法简介

    1. Before:Advice,具体插入位置
    2. execution:处理Join Point的类型,call、execution
    3. 匹配规则
    4. onActivityCalled:要插入的代码

3-7 优雅获取方法耗时实操

具体实现见:PerformanceAop

优点:无侵入性、修改方便

3-8 异步优化详解

  1. 优化技巧

    Theme切换:感觉上的快

    步骤

    1. lanucher.xml

    2. <activity android:theme="@style/Theme.Splash">

    3. @Override
      protected void onCreate(Bundle savedInstanceState) {
      		// super.onCreate之前切换回来
              setTheme(R.style.AppTheme); 
              super.onCreate(savedInstanceState);
      }
  2. 异步优化

    核心思想:子线程分担主线程任务,并行减少时间

            // 线程池
            ExecutorService service = Executors.newFixedThreadPool(CORE_POOL_SIZE);
            service.submit(new Runnable() {
                @Override
                public void run() {
                    initBugly();
                }
            });
            // ...
    		// 必须被满足一次
        	CountDownLatch mCountDownLatch = new CountDownLatch(1);
            service.submit(new Runnable() {
                @Override
                public void run() {
                    // 需要在某阶段完成
                    initBugly();
                    mCountDownLatch.countDown();
                }
            });
            try {
            	// 等待
                mCountDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

异步优化注意事项:

  1. 不符合异步要求
  2. 需要在某阶段完成
  3. 区分CPU密集型和IO密集型任务

3-9 异步初始化最优解-启动器

  1. 常规异步痛点

    1. 代码不优雅
    2. 场景不好处理(依赖关系)
    3. 维护成本高
  2. 启动器介绍

    核心思想:充分利用CPU多核,自动梳理任务顺序

    启动器流程

    1. 代码Task化,启动逻辑抽象为Task
    2. 根据所有任务依赖关系排序生成一个有向无环图
    3. 多线程按照排序后的优先级依次执行
  3. 启动器实战

            TaskDispatcher.init(PerformanceApp.this);
    
    		TaskDispatcher dispatcher = TaskDispatcher.createInstance();
    
            dispatcher.addTask(new InitAMapTask())
                    .addTask(new InitStethoTask())
                    .addTask(new InitWeexTask())
                    .addTask(new InitBuglyTask())
                    .addTask(new InitFrescoTask())
                    .addTask(new InitJPushTask())
                    .addTask(new InitUmengTask())
                    .addTask(new GetDeviceIdTask())
                    .start();
    
            dispatcher.await();

3-11 更优秀的延迟初始化方案

  1. 常规方案

    1. New Handler().postDelayed

    2. 数据展示后调用

    3. new DispatchRunnable(new DelayInitTaskA()).run();
      new DispatchRunnable(new DelayInitTaskB()).run();

    常规初始化痛点:

    1. 时机不便控制
    2. 导致页面卡顿
  2. 更优方案

    核心思想:对延迟任务分批初始化

    利用IdleHandler特性,空闲执行

            DelayInitDispatcher delayInitDispatcher = new DelayInitDispatcher();
            delayInitDispatcher.addTask(new DelayInitTaskA())
                    .addTask(new DelayInitTaskB())
                    .start();

    优点:

    1. 执行时机明确
    2. 缓解页面卡顿

3-12 启动优化其它方案

  1. 优化总方针
    1. 异步、延迟、懒加载
    2. 技术、业务相结合
  2. 注意事项
    1. wall time与cpu time
      1. cpu time才是优化方向
      2. 按照systrace及cpu time跑满cpu
    2. 监控的完善
      1. 线上监控多阶段时间(App、Activity、生命周期间隔时间)
      2. 处理聚合看趋势
    3. 收敛启动代码修改权限
      1. 结合ci修改启动代码需要Review或通知
  3. 其它方案
    1. 提前加载SharedPreferences
      1. Multidex之前加载,利用此阶段cpu
      2. 复写getApplicationContext()返回this
    2. 启动阶段不启动子进程
      1. 子进程会共享CPU资源,导致主进程CPU紧张
      2. 注意启动顺序:App onCreate 之前是ContentProvider
    3. 类加载优化:提前异步类加载
      1. Class.forName() 只加载类本身及其静态变量的引用类
      2. new 类实例可以额外加载类成员变量的引用类
    4. 启动阶段抑制GC
    5. CPU锁频

3-14 启动速度模拟面试

  1. 你做启动优化是怎么做的?
    1. 分析现状、确认问题
    2. 针对性优化
    3. 长期保持优化效果
  2. 是怎么异步的,异步遇到问题没有
    1. 体现演进过程
    2. 详细介绍启动器
  3. 你做了启动优化,觉得有哪些容易忽略的注意点
    1. cpu time与wall time
    2. 注意延迟初始化的优化
    3. 介绍下黑科技
  4. 版本迭代导致的启动变慢有好的解决方式吗
    1. 启动器
    2. 结合CI
    3. 监控完善