1.App启动流程
app启动流程.jpg- 点击桌面App图标,Launcher进程采用Binder IPC向system_server进程发起startActivity请求。
- system_server进程接收到请求后,向Zygote进程发送创建进程的请求。
- Zygote进程fork出新的子进程,即App进程
- App进程通过Binder IPC向system_server进程发起attach Application请求
- system_server进程收到请求后,进行一系列准备工作后,再通过Binder IPC向App进程发送scheduleLaunchActivity请求。
- App进程的binder线程(ApplicationThread)在收到请求后,通过handler向主线程发送LAUNCHER_ACTIVITY消息。
- 主线程收到Message后,通过反射机制创建目标Activity,并回调Activity.onCreate()等方法。
- 到此,App便正式启动,开始进入Activity生命周期,执行完onCreate/onStart/onResume方法,UI渲染结束后便可以看到App的主界面。
2.启动状态
应用有三种启动状态,每种状态都会影响应用向用户显示所需要的时间:
-
冷启动
系统不存在App进程(App首次启动或App被完全杀死)时启动App- 第一阶段
1、加载并启动app
2、启动后立即显示一个空白的启动窗口
3、创建app进程 - 第二阶段
1、创建app对象
2、启动主线程
3、创建主Activity
4、加载布局
5、布置屏幕
6、首帧绘制
- 第一阶段
-
热启动
当我们按下Home键或其它情况app被切换到后台,再次启动app的过程。热启动时,系统将activity带回前台,如果应用程序的所有activity仍驻留在内存中,应用不必重复执行对象初始化、布局加载和绘制。
-
温启动
温启动包含了冷启动的一些操作,由于app进程依然在,温启动只执行冷启动的第二阶段,这代表中它比热启动有更多的开销。如:用户按返回键退出应用,然后又重新启动它;系统回收了app的内存,然后重新启动app。
3.冷启动耗时统计
性能测试中存在2-5-8原则:2s内很快,2~5s 还可以,5~8s 很慢还可以接受,8s糟糕透了。
Google 提出一项计划Android Vitals:冷启动5s内,温启动2s内,热启动1.5s内。
-
系统日志统计
Android Studio Logcat包含一行输出,名为Displayed的值,表示从启动进程到屏幕上完成对应Activity绘制所用的时间。ActivityTaskManager: Displayed com.azxc.easyworkapp.test/com.azxc.easyworkapp.ui.LoginActivity: +1s78ms
-
adb命令统计
adb命令统计启动耗时.png
adb shell am start -S -W [packageName]/[activityName]
4.CPU Profile
我们可以通过CPU Profiler查看应用在某段时间里某个线程执行了哪些方法,并且还定量的展示了执行这些方法所耗费的时间及其方法的调用堆栈。 cpu profile.pngCPU Profile只支持Android 8.0以上,其它版本可以用Debug API生成trace
public class MyApplication extends Application {
public MyApplication(){
//开始跟踪
Debug.startMethodTracing("trace");
}
//...
}
public class MainActivity extends AppCompatActivity{
@Override
public void onWindowFocusChanged(booleanhasFocus){
super.onWindowFocusChanged(hasFocus);
//停止跟踪
Debug.stopMethodTracing();
}
//...
}
运行app会生成.trace文件,用Android Studio打开即可。
5.StrictMode
严苛模式是一个开发工具,能够检测程序中的违例,从而修复。最常用于主线程中磁盘读写和网络访问。
public class MyApplication extends Application {
public void onCreate() {
if (BuildConfig.DEBUG) {
//线程检查策略
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads() //读磁盘
.detectDiskWrites()//写磁盘
.detectNetwork() //检查网络
.penaltyLog()
.build());
//VM检查策略
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects() //Sqlite对象,如cursors
.detectLeakedClosableObjects() //未关闭的Closeable对象
.penaltyLog() //违规打印日志
.penaltyDeath() //违规崩溃
.build());
}
super.onCreate();
}
//...
}
检测项
- ThreadPolicy
- detectAll 检测所有潜在的违例
- detectCustomSlowCalls 自定义耗时操作
- detectDiskReads 读磁盘
- detectDiskWrites 写磁盘
- detectNetwork 检查网络
- detectResourceMismatches 检查资源类型是否匹配
- VmPolicy
- detectAll 检测所有潜在的
- detectActivityLeaks 检测Activity的泄露
- detectCleartextNetwork 检测明文的网络
- detectFileUriExposure 检测file://或者是content://
- detectLeakedClosableObjects 检查为管理的Closable对象
- detectLeakedRegistrationObjects 检测需要注册类型是否解注
- detectLeakedSqlLiteObjects 检测sqlite对象,如cursors
检测到违规项之后的表现形式
- penaltyDeath crash,在所有表现形式最后运行,
- penaltyDeathOnNetwork crash,在所有值钱,必须调用detectNetwork去允许这个。
- penaltyDialog 弹出dialog
- penaltyDropBox 将日志吸入到dropbox中
- penaltyFlashScreen 屏幕闪烁
- penaltyLog log日志
6.启动优化相关
1.异步加载:耗时多的加载放到子线程中异步执行
2.延迟加载: 非必须的数据延迟加载
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
XXX.init();
return false;
}
});
3.提前加载:利用ContentProvider提前进行初始化
网友评论