一、前言:
用户希望应用能够及时响应并快速加载。启动时间过长的应用可能会导致用户在对应用给出很低的评分,甚至完全
弃用。
1、启动流程
①点击桌面App图标,Launcher进程采用Binder IPC向system_server进程发起startActivity请求;
②system_server进程接收到请求后,向zygote进程发送创建进程的请求;
③Zygote进程fork出新的子进程,即App进程;
④App进程,通过Binder IPC向sytem_server进程发起attachApplication请求;
⑤system_server进程在收到请求后,进行一系列准备工作后,再通过binder IPC向App进程发送scheduleLaunchActivity请求;
⑥App进程的binder线程(ApplicationThread)在收到请求后,通过handler向主线程发送LAUNCH_ACTIVITY消息;
⑦主线程在收到Message后,通过反射机制创建目标Activity,并回调Activity.onCreate()等方法。
⑧到此,App便正式启动,开始进入Activity生命周期,执行完onCreate/onStart/onResume方法,UI渲染结束后便可以看到App的主界面。
2、启动状态
应用有三种启动状态,每种状态都会影响应用向用户显示所需的时间:冷启动、温启动与热启动。
- 冷启动:
冷启动是指应用从头开始启动:系统进程在冷启动后才创建应用进程。发生冷启动的情况包括应用自设备启动后或系统终止应用后首次启动。
- 热启动:
在热启动中,系统的所有工作就是将 Activity 带到前台。只要应用的所有 Activity 仍驻留在内存中,应用就不必重复执行对象初始化、布局加载和绘制。
- 温启动:
温启动包含了在冷启动期间发生的部分操作;同时,它的开销要比热启动高。有许多潜在状态可视为温启动。例如:
- 用户在退出应用后又重新启动应用。进程可能未被销毁,继续运行,但应用需要执行 onCreate() 从头开始重新创建 Activity。
- 系统将应用从内存中释放,然后用户又重新启动它。进程和 Activity 需要重启,但传递到 onCreate() 的已保存的实例savedInstanceState对于完成此任务有一定助益。
…
3、冷启动耗时统计
在性能测试中存在启动时间2-5-8原则:
- 当用户能够在2秒以内得到响应时,会感觉系统的响应很快;
- 当用户在2-5秒之间得到响应时,会感觉系统的响应速度还可以;
- 当用户在5-8秒以内得到响应时,会感觉系统的响应速度很慢,但是还可以接受;
- 而当用户在超过8秒后仍然无法得到响应时,会感觉系统糟透了,或者认为系统已经失去响应。
4、启动耗时统计
1、系统日志统计
在 Android 4.4(API 级别 19)及更高版本中,logcat 包含一个输出行,其中包含名为 Displayed 的值。此值代表从启动进程到在屏幕上完成对应 Activity 的绘制所用的时间。
2、adb命令统计
adb shell am start -S -W [packageName]/[activityName]!
启动完成后,将输出:
在这里插入代码片
ThisTime: 415
TotalTime: 415
WaitTime: 437
WaitTime:总的耗时,包括前一个应用Activity pause的时间和新应用启动的时间;
- ThisTime表示一连串启动Activity的最后一个Activity的启动耗时;
- TotalTime表示新应用启动的耗时,包括新进程的启动和Activity的启动,但不包括前一个应用Activity pause
的耗时。- 开发者一般只要关心TotalTime即可,这个时间才是自己应用真正启动的耗时。
5、CPU Profile配置
要在应用启动过程中自动开始记录 CPU 活动,请执行以下操作:
- 依次选择 Run > Edit Configurations。 2. 在 Profiling 标签中,勾选 Start recording CPU activity on startup 旁边的复选框。
- 在 Profiling 标签中,勾选 Start recording CPU activity on startup 旁边的复选框。
- 从菜单中选择 CPU 记录配置。
- Sample Java Methods
对 Java 方法采样:在应用的 Java 代码执行期间,频繁捕获应用的调用堆栈。分析器会比较捕获的数据集,
以推导与应用的 Java 代码执行有关的时间和资源使用信息。如果应用在捕获调用堆栈后进入一个方法并在下
次捕获前退出该方法,分析器将不会记录该方法调用。如果您想要跟踪生命周期如此短的方法,应使用检测
跟踪。- Trace Java Methods
跟踪 Java 方法:在运行时检测应用,以在每个方法调用开始和结束时记录一个时间戳。系统会收集并比较这
些时间戳,以生成方法跟踪数据,包括时间信息和 CPU 使用率。- Sample C/C++ Functions
对 C/C++ 函数采样:捕获应用的原生线程的采样跟踪数据。要使用此配置,您必须将应用部署到搭载
Android 8.0(API 级别 26)或更高版本的设备上。- Trace System Calls
跟踪系统调用:捕获非常翔实的细节,以便您检查应用与系统资源的交互情况。您可以检查线程状态的确切
时间和持续时间、直观地查看所有内核的 CPU 瓶颈在何处,并添加要分析的自定义跟踪事件。要使用此配
置,您必须将应用部署到搭载 Android 7.0(API 级别 24)或更高版本的设备上。
此跟踪配置在 systrace 的基础上构建而成。您可以使用 systrace 命令行实用程序指定除 CPU Profiler 提供的
选项之外的其他选项。systrace 提供的其他系统级数据可帮助您检查原生系统进程并排查丢帧或帧延迟问
题。
- 点击 Apply。
- 依次选择 Run > Profile,将您的应用部署到搭载 Android 8.0(API 级别 26)或更高版本的设备上。
6、StrictMode
StrictMode是一个开发人员工具,它可以检测出我们可能无意中做的事情,并将它们提请我们注意,以便我们能够修复它们。
StrictMode最常用于捕获应用程序主线程上的意外磁盘或网络访问。帮助我们让磁盘和网络操作远离主线程,可以使应用程序更加平滑、响应更快。
public class MyApplication extends Application {
@Override
public void onCreate() {
@Override public void onCreate () {
if (BuildConfig.DEBUG) {
//线程检测策略
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads() //读、写操作
.detectDiskWrites()
.detectNetwork() // or .detectAll() for all detectable problems
.penaltyLog()
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects() //Sqlite对象泄露
.detectLeakedClosableObjects() //未关闭的Closable对象泄露
.penaltyLog() //违规打印日志
.penaltyDeath() //违规崩溃
.build());
}
}
}
7、启动优化相关
1). 合理的使用异步初始化、延迟初始化、懒加载机制。
2). 启动过程避免耗时操作,如数据库 I/O操作不要放在主线程执行。
3). 类加载优化:提前异步执行类加载。
4). 合理使用IdleHandler进行延迟初始化。
5). 简化布局
6). AsyncLayoutInflater 「异步加载布局」实现