1. 前言

一个应用App的启动速度能够影响用户的首次体验,启动速度较慢(感官上)的应用可能导致用户再次开启App的意图下降,或者卸载放弃该应用程序。本文会通过以下几个方面来介绍应用启动的相关指标和优化,提供应用的启动速度。

整体文章思路如下:

启动优化

2. 冷启动&热启动

通常来说,启动方式分为两种:冷启动和热启动。

  1. 冷启动:当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用,这个启动方式就是冷启动。
  2. 热启动:当启动应用时,后台已有该应用的进程(例:按back键、home键,应用虽然会退出,但是该应用的进程是依然会保留在后台,可进入任务列表查看),所以在已有进程的情况下,这种启动会从已有的进程中来启动应用,这个方式叫热启动。

两者之间的特点如下:

  • 冷启动:系统会重新创建一个新的进程分配给该应用,从Application创建到UI绘制等相关流程都会执行一次。
  • 热启动:应用还在后台,因此该启动方式不会重建Application,只会重新绘制UI等相关流程。

冷热启动时间的计算命令:

adb shell am start -W [packageName]/[packageName.XxxActivity]
  • 参数说明:
    1、ThisTime:一般和TotalTime时间一样。除非在应用启动时开了一个透明的Activity预先处理一些事再显示出主Activity,这样将比TotalTime小。
    2、TotalTime:应用的启动时间。包含创建进程+Application初始化+Activity初始化到界面显示。
    3、WaitTime:一般比TotalTime大点,包含系统影响的耗时。
    对于我们的应用来说结果如下:
  • 冷启动

冷启动

  • 热启动

热启动

可以看到两者时间相差比较大。
根据该命令基本可以看出一个应用的启动速度了,从冷启动热启动的相关关系,当我们需要优化启动速度的时候,优化冷启动速度即可。
但是该命令我们只是大概知道应用的启动速度,但并不知道我们的应用具体哪个位置耗时,影响启动速度,后续我会介绍如何获取启动具体耗时时间。

3. 常规获取时间方法

常规获取时间方法无非就是在方法执行前记录下时间,在方法执行完毕后记录时间,两者时间之差就是该方法执行的时间,封装一个基础类如下:

public class LaunchTimer { private static final String TAG = "LaunchTimer"; private static long sTime; public static void startRecord() { sTime = System.currentTimeMillis(); } public static void endRecord() { long cost = System.currentTimeMillis() - sTime; NLog.i(TAG, "执行耗时:%s", cost); }}

使用方式如下,可以直观的看出createController方法执行的时间

createController耗时

这样已经很直观了,可以具体到该方法的执行时间,如果要继续分析则对该方法内部继续执行该代码即可。但是这里有一个问题如果要知道10个或者更多方法的执行时间,这个方法看起来是可以,但写起来过于繁琐,且不符合程序员的习惯,关于这种场景后面会介绍如何处理。

4. TraceView和SysTrace工具使用

  • TraceView使用:TraceView是Android平台配备一个很好的性能分析工具,它可以通过图形化的方式让我们了解我们要跟踪的程序的性能,并且能具体到方法。
    使用方式:
  1. 通过Android studio自带的traceview查看(Android profiler)。
  2. 通过Android SDK自带的Debug。
  3. 通过DDMS中的traceview查看。
    本文主要介绍第二种方式,通过sdk中的方法,对应用进行打点获取相关信息:
 @Override public void onCreate(final Bundle icicle) { setTheme(R.style.BrowserTheme); Intent intent = getIntent(); NLog.i(LOGTAG,"onCreate"); super.onCreate(icicle); //开始记录,且该方法可以设置文件大小和路径 Debug.startMethodTracing("browser.trace"); Controller controller=createController(); mController = controller; getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN|View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); controller.handleThirdPartyIntent(intent); //结束记录 Debug.stopMethodTracing(); }

如上可以在目录下可以生成如下文件

/sdcard/Android/data/com.xxx.xx.browser/files/browser.trace

导出改文件,通过Android Studio的profile打开改文件

traceview

1处可以看出有多少线程。
2处可以看出具体方法的耗时。
3处有两个选项:

  • wall clock time:代码在线程上执行的真正时间[有一部分是等待cpu轮询时间]
  • thread time :cpu执行的时间
    一般是优化的是cpu执行时间
    结合业务代码走查发现Controller0线程为一个线程,因此主线程一些操作可以放进去执行,从而减少main线程的耗时。走查代码可以发现在Controller0线程中执行如下
 requestPermission(); ExecutorService service = Executors.newSingleThreadExecutor(new NamedThreadFactory("Controller")); Future future = service.submit(new Callable() { @Override public Boolean call() throws Exception { try { asyncInit(); } catch (Exception e) { return false; } return true; } });

requestPermission()方法执行在main线程中,因此我们可以把其放在Controller0线程中执行,从而减少main线程的的时间

 ExecutorService service = Executors.newSingleThreadExecutor(new NamedThreadFactory("Controller")); Future future = service.submit(new Callable() { @Override public Boolean call() throws Exception { try { requestPermission(); asyncInit(); } catch (Exception e) { return false; } return true; } });

经测试发现无问题,且对比此时的trace文件发现修改前后main线程时间相对来说减少很多。

  • SysTrace使用:
    SysTrace用于收集可帮助您检查原生系统进程的详细系统级数据,例如CPU调度、磁盘活动、应用线程等,并解决掉帧引起的界面卡顿。
    使用方式:

在代码的开始位置加上tag

 TraceCompat.beginSection("AppOnCreate");

然后指定位置结束

TraceCompat.endSection();

即可以抓取到整个应用在此过程的相关信息,例如在onCreate方法中添加上述两行代码,执行相关python命令:

python systrace.py -b 32768 -t 10 -a com.xxx.xxx.browser -o browser.html sched gfx view wm am app

操作相关应用,即可以抓取整个过程的相关信息:

systrace

即可以看到添加的tag“AppOnCreate”,对应的时间信息:

  1. Wall Duration 代表的方法从开始到结束的耗时
  2. CPU Duration 代表CPU的执行时间
    通过这两个参数可以看出此流程中执行的时间等相关信息
    我们都知道CPU是轮询模式,因此优化的方向可以说是两个方向,提高CPU的核数和优化CPU执行的时间。

5. 通过AOP获取时间

  • AOP:面向切面编程(Aspect-Oriented Programming)。如果说,OOP如果是把问题划分到单个模块的话,那么AOP就是把涉及到众多模块的某一类问题进行统一管理。打个比方Android 里面PMS,AMS都拥有各自的职责,但是他们都需要通过log系统管理log,这就是一种AOP思想。

AspectJ实际上是对AOP编程思想的一个实践,当然,除了AspectJ以外,还有很多其它的AOP实现,例如ASMDex,但目前最好、最方便的,依然是AspectJ。
AspectJ的使用如下:
根目录gradle下引用:

 classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.0'

app目录gradle文件下引用:

 implementation 'org.aspectj:aspectjrt:1.8.+'

此两处引用完成之后,就是代码编写:

package com.xx.xxx.browser.aspect;import android.util.Log;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.Signature;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;@Aspectpublic class IntercepLifeCycleAOP { //获取该Activity下的所有on开头的方法耗时 @Around("execution(* com.xxx.xxx.BrowserActivity.on**(..))") public Object getTime(ProceedingJoinPoint joinPoint) { Object proceed = null; long start = System.currentTimeMillis(); try { proceed = joinPoint.proceed(); } catch (Throwable throwable) { throwable.printStackTrace(); } long end = System.currentTimeMillis(); Log.d("IntercepLifeCycleAOP", joinPoint.getSignature().getName() + ":执行时间:" + (end - start)); return proceed; }}

引入之后结果如下:

AspectJ

可以看到具体方法的耗时。
采用注解方式,其中Around 需要有一定的AspectJ相关的语法

6. 用户体验优化

  1. 主题优化:通过给应用设置一个透明主题,在应用启动完成之后,再给其赋予本该有的主题,通过对启动页的主题设置后,就会将白屏/黑屏抹去,用户点击App的图标就展示启动图,让用户先产生启动很快的“错觉”。
  2. 动画兼容:根据不同年代的机型可以选择执行或不执行相关动画,或者延迟其他相关操作,可根据device-year-class来判断具体年份
  3. UI布局优化。

7. 异步加载

1.采用线程加载一些资源,比如sdk初始化,配置信息拉取等相关资源。线程,线程池,IntentServices均可以,配合延迟效果更好。

2.当我们采用线程之间的可能会存在各线程之间相互等待依赖等相关问题,资源A线程必须在资源B加载完成,才能加载,但两者又会在不同的线程之间,此时简单的办法可以采用CountDownLatch来实现。其整体思路如下图

CountDownLatch.png

3.使用 Pipeline 机制,根据业务优先级规定业务初始化时机,制定启动框架,它们为各个任务建立依赖关系,最终构成一个有向无环图。对于可以并发的任务,会通过线程池最大程度提升启动速度。无论是微信的mmkernel 还是阿里的Alpha 都具备这种能力。

4.其他方案:
除了上述几种,我们也可以利用IdealHandler,dex分包等相关方式做到启动优化。

8. 总结

上面主要介绍了如何获取启动的相关事件和相关优化知识点。关于时间就是尽量使用工具,关于优化整体思路就是能预加载能延迟加载的资源尽量去预加载去延迟加载,能异步的业务尽量异步。
当然优化这个话题也是要根据具体的业务逻辑来定,总之:

对于启动优化要警惕 KPI 化,我们要解决的不是一个数字,而是用户真正的体验问题。

上述只是提供一些思路和方式,还有很多奇淫技巧,欢迎给位大佬评论指出。


感谢大家能耐着性子看完啰里啰嗦的文章

在这里我也分享一份私货,自己收录整理的Android学习PDF+架构视频+面试文档+源码笔记,还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习

如果你有需要的话,可以点赞+评论+转发关注我,然后私信我【进阶】我发给你

Android Studio 忽略_Android性能优化--启动优化相关推荐

  1. android系统功耗优化(2)---Android最佳实践之性能 - 电池续航时间优化

    Android最佳实践之性能 - 电池续航时间优化 Doze和App Standby的优化(API23) 参考地址:http://developer.android.com/training/moni ...

  2. Android Studio 4.0 新功能与优化

    1.前言 Android Studio又更新了,每次重大更新都给我们的生产力提升了一个台阶,当然也会带来神奇的bug,墙裂提醒各位小伙伴升级请慎重!!! [真香警告]Android Studio下载链 ...

  3. Android Studio CPU profiler性能分析工具介绍和使用详解

    Android Studio CPU profiler性能分析工具介绍和使用详解 CPU profiler介绍 Android Studio CPU 性能剖析器可实时检查应用的 CPU 使用率和线程活 ...

  4. Android studio 使用androidX后应用启动log中报Didn‘t find class “android.view.View$OnUnhandledKeyEventListener“

    Didn't find class "android.view.View$OnUnhandledKeyEventListener" Android studio 使用android ...

  5. Android 性能优化—— 启动优化提升60,android蓝牙开发实例

    其实这种方式并没有真正的加速应用进程的启动速度,而只是通过用户视觉效果带来的优化体验. _3_代码优化 当然上面使用设置主题的方式优化用户体验效果治标不治本,关键还在于对代码的优化. 首先我们可以统计 ...

  6. 【Android 性能优化】应用启动优化 ( 启动优化项目 | 界面启动时间 | 启动优化项目 | 方法追踪 MethodTracing )

    文章目录 一. 界面启动时间 二. 启动优化项目 三. 方法追踪 一. 界面启动时间 在 [Android 性能优化]应用启动优化 ( 启动白屏问题 | 应用启动时间测量 | 冷启动 | 热启动 | ...

  7. Android 性能优化—— 启动优化提升60,Android开发全套学习

    在入口 Acitivity 中开启 IntentService 来下载广告页. 或者是其它异步下载操作. 在广告页图片 文件流完全写入后 记录图片大小,或者记录一个标识. 在下次的广告页加载中可以判断 ...

  8. Android篇 | 爱奇艺App启动优化实践分享

    导读 性能优化一直都是各个APP推进中的重点.难点,爱奇艺 App也不例外.在此之前,爱奇艺App Android 版的启动速度虽然一直处于同类App领先的水平,但优势距离其他同类的APP距离一直很小 ...

  9. iOS性能优化 - 启动优化

    APP的启动可以分为2种 冷启动(Cold Launch):从零开始启动APP: 热启动(Warm Launch):APP已经在内存中,在后台存活着,再次点击图标启动APP. APP启动时间的优化,主 ...

最新文章

  1. 浅谈MySQL存储引擎-InnoDBMyISAM
  2. Emacs 24.3 配置JDEE(http://blog.csdn.net/csfreebird/article/details/19033939)
  3. MySQL • 源码分析 • 内存分配机制
  4. 编程语言50年来的变化,我用50种编程语言告诉你“Hello world”怎么写!
  5. 九度OJ 1435:迷瘴
  6. Windows 10下高效工作——快捷键一览
  7. Matrix Chain Multiplication (堆栈)
  8. 存储过程,触发器,Mysql权限,备份还原
  9. xml和TreeView
  10. 三菱plc pwm指令_三菱PLC初学者只要解决这50个问题,那你就觉得很容易上手?
  11. LAMMPS学习总结2
  12. 在mac上开启httpServer服务
  13. UWB电厂人员定位系统优势有哪些?
  14. 基于MicroStation CE的点云软件二次开发
  15. 任务栏WPS出现多窗口预览?下载这个注册表就对了
  16. latex 特殊符号[箭头/希腊]
  17. 淘淘商城第24讲——实现商品类目的选择
  18. 数字IC验证:Hands-on Coding之Harness Interface与内部的Interfaces
  19. JDK8新特性-Map遍历比较
  20. 啊,整理整理收藏的PS3游戏

热门文章

  1. Create-React-App创建antd-mobile开发环境
  2. 使用Angularjs的ng-cloak指令避免页面乱码
  3. windows下python Tkinner环境布置(包含PIL环境安装)
  4. 【BZOJ 1095】 [ZJOI2007]Hide 捉迷藏 括号序列
  5. Hover属性的充分利用
  6. IE6给我网站开发带来的问题
  7. 10个好用的Web日志安全分析工具
  8. Linux系列 | 了解nohup和的功效
  9. rm删除报错 :-bash: syntax error near unexpected token `('
  10. VBA代码执行过程中,显示程序的运行状态