Android 冷启动系统优化(附实践思路)

思路分析

前言

冷启动涉及的因素很多,从流程上说,分为以下几个阶段

  1. 点击Launcher的图标,AMS处理intent,与Zygote socket交互fork进程,新进程运行ActivityThread代码,AMS和ApplicationThread互相绑定,AMS发binder信息反射启动Application。以上是第一阶段,这个阶段到Application的attchbasecontext方法之前,我们基本上都无法参与,但ContentProvider的初始化是在Application之前的,它的onCreate方法运行在主线程,这个也需要关注一下耗时问题。
  2. 从Application的attchbasecontext开始,是第二阶段,这个阶段经历以下几个流程。Application的init方法,attchbasecontext方法,onCreate方法,SplashActivity的生命周期,最后跳转到主Activity的过程。这个过程中会初始化大量的三方组件和业务组件,其中就包含了耗时方法,如果项目比较旧,还会有很多冗余的逻辑和代码,依赖关系等错综复杂。这时候优化就必须进行了。
优化逻辑
一、分析耗时

首先要找到耗时的方法,卡顿的原因才能继续,不然优化半天我们为了啥?

网上有很多方法,简单列几个

  1. Logcat打日志,这个就不多说了,**过滤关键字“Displayed”**就可以看到

  2. adb shell

    // 其中的AppstartActivity全路径可以省略前面的packageName
    adb shell am start -W [packageName]/[AppstartActivity全路径]
    

    通过这个方法可以看懂ASM启动Activity的耗时,非准确

  3. Logcat代码打点,在启动的关键节点打耗时方法,计算差值

  4. AOP:此方法灵活应用around,before,after等关键词对方法进行耗时打印,了解更多可以搜索引擎解决

  5. TraceView和Systrace,有需要可以搜索引擎解决

    TraceView:Android studio自带的ProFiler就可以查看,耗时非常不准确。或者可以在开始记录的点写上代码Debug.startMethodTracing(“tracePath”),在终止记录的点写上代码Debug.stopMethodTracing()。通过adb pull /mnt/sdcard/tracePath.trace .将trace导出指定的文件夹中,通过Android studio打开trace文件,界面同CPU Profiler差不多。

    Systrace在系统的一些关键链路(如SystemServcie、虚拟机、Binder驱动)插入一些信息(Label)。然后,通过Label的开始和结束来确定某个核心过程的执行时间,并把这些Label信息收集起来得到系统关键路径的运行时间信息,最后得到整个系统的运行性能信息

  6. ASM插装,使用GradlePlugin编写插件,利用ASM在Transform过程中对工程方法耗时进行打印。

我选择的是最后一种方法,这种方法的优势是,打成正式包之后对log的日志进行分析,对函数本身的耗时影响较小准确性高。但是缺点就是无法和分析工具一样,获得更多的硬件信息。

二、优化工具
  1. 主题切换:在Activity的windowBackground主题属性预先设置一个启动图片(layer-list实现),在启动后,在Activity的onCreate()方法中的super.onCreate()前再setTheme(R.style.AppTheme)。

  2. 懒加载:注意和延时加载不同,是在需要使用的时候才加载。

  3. 异步加载:这里需要了解线程池、线程池调优、和任务异步相关的知识。通过CPU核心数量等相关信息,开辟CPU密集线程池和IO密集线程池,把不必须同步加载的任务异步加载。这里可以自己写一个启动bootmanager来统一管理同步和异步任务。

  4. 延时加载:延时加载解决的问题是必须同步加载,但是又不急需的任务。延时加载可以将其执行顺序往后调。来达到降低耗时的目的。这里可以开发一个lazybootmanager来统一管理延时任务

  5. Multidex优化:这个只针对Android5.0以下的机型,直接使用字节BoostMultiDex插件即可,有需要搜索引擎解决。

  6. 内存抖动:减少临时变量的使用,和不必要的GC,这个得结合项目及代码进行优化。

  7. 耗时方法:将耗时方法异步执行,再保存静态结果,以供同步方法使用。这里需要做容错,如果异步方法没执行出结果,那么再同步调用一遍,以保执行结果的正确性。

  8. 类加载优化:new 实例中有很大一部分时间是load相应的类到方法区,非常耗时,需要优化。

  9. WebView启动:使用WebView缓存池,用到WebView的时候都从缓存池中拿,注意内存泄漏问题。

  10. IO优化业务数据预加载、数据库提前读取数据。|| xml结构优化,比如启动页就简单的FrameLayout加图片等形式

  11. 子进程优化:启动阶段减少子进程的启动等。

实践思路

1、耗时

使用Plugin插件+ASM字节码插装的方式进行方法耗时打印。

ASM插装代码可以参考ASMPlugin插件(Android Studio)进行分析,降低难度。

2、同步&异步加载框架

这里可以去github上找到很多开源的bootmanger框架,没必要自己写,但需要实现以下几种功能。

1、任务依赖:必须解决任务之间的依赖关系,这个可以参考单向无环拓补图算法进行实现。

2、任务优先级:同步方法直接的优先级、异步方法之间的优先级。各自灵活设置,保证优化的有效性。

3、线程池:必须通过CPU等硬件信息设置CPU密集的线程池。

4、任务解耦:这个基本上没啥问题,但也要注意。

5、任务区分:主进程任务、主线程任务、运行进程等一系列问题。

3、懒加载框架

这个同样去github找,注意以下几点就行。

1、触发时机:一般是mainActivity的idelHandler时机触发,注意多次idel触发多个任务,不要一次全部执行,影响用户使用,可以使用优先队列实现。

2、任务性质:延时加载解决的问题是必须同步加载,但是又不急需的任务。如果可以异步,直接给异步框架即可。

4、IO&内存抖动

1、数据库,SP文件异步读取到内存中,减少查询耗时

2、xml资源文件简化,SplashActivity耗时同步方法异步,注意容错。**不推荐使用X2C和AsyncLayoutInfalter进行优化,对于冷启动意义不大。**他们可以用于页面启动优化,限制较多,需要注意时机和限制。

3、减少引用临时变量的使用,如果临时变量太多内存抖动触发GC,得不偿失。

5、类加载优化

这里可以通过异步提前new或者Class.forName()对象让它先加载到方法区,减少耗时。

注意:

Class.forName()只加载类本身及其静态变量的引用类。

new 类实例 可以额外加载类成员变量的引用类。

思路总结

经过上述的优化之后,其实就已经没有什么太大的问题了。最重要的还是结合业务进行优化。这里只给出了思路,具体的实现可以参考开源框架。我提供方向,你自己努力,加油!!!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值