目录
1.冷启动
1.1冷启动是什么?
1.2.冷启动流程分析
1.3冷启动优化
1.3.1黑白屏问题
1.3.2APP启动时间过长问题
1.3.3解决APP启动时间过长问题
2.温启动
2.1从用户体验分析
3.热启动
目录
1.冷启动
1.1冷启动是什么?
1.2.冷启动流程分析
1.3冷启动优化
1.3.1黑白屏问题
1.3.2APP启动时间过长问题
1.3.3解决APP启动时间过长问题
2.温启动
2.1从用户体验分析
3.热启动
4.其他
通过APP启动时都会有一个Splash过度页面,Splash过度页面会显示广告;
a.在第一次点击icon正常启动APP时我们会发现总会有白屏或者黑屏的情况;(冷启动)
b.通过返回按钮关闭APP,点击icon重新打开APP可能也会出现白屏或者黑屏;(温启动)
c.通过home回到Home界面,在内存较低的情况下,点击icon重新打开APP可能也会出现白屏或者黑屏;(热启动)
为了改善用户体验,不让用户看到白屏或者黑屏,同时让用户快速进入到APP,在APP启动的时候做一些优化;
应用有三种启动状态,每种状态都会影响应用向用户显示所需的时间:冷启动、温启动或热启动。在冷启动中,应用从头开始启动。在其他状态下,系统需要将后台运行中的应用带入前台。建议您始终在假定冷启动的基础上进行优化。这样做也可以提升温启动和热启动的性能。
冷启动是指应用从头开始启动:系统进程在冷启动后才创建应用进程。发生冷启动的情况包括应用自设备启动后或系统终止应用后首次启动。这种启动给最大限度地减少启动时间带来了最大的挑战,因为系统和应用要做的工作比在其他启动状态下更多。
当应用启动时,空白启动窗口将保留在屏幕上,直到系统首次完成应用绘制。完成后,系统进程会换掉应用的启动窗口,允许用户开始与应用互动。
当第一次点击APP的icon时会分为两个阶段:
1)不可控阶段
点击app
以后到初始化Application
之间这段时间,系统接管,从Zygote
进程中fork
创建新进程,GC
回收等等一系列操作;
在冷启动开始时,系统有三个任务。这三个任务是:
a.加载并启动应用;
b.在启动后立即显示应用的空白启动窗口;
c.创建应用进程;
2)可控阶段
系统一创建应用进程,应用进程就负责后续阶段,初始化Application
开始:
a.创建应用对象(Application);
b.启动主线程。
c.创建主 Activity。
d.扩充视图。
e.布局屏幕。
f.执行初始绘制。
一旦应用进程完成第一次绘制,系统进程就会换掉当前显示的后台窗口,替换为主 Activity。此时,用户可以开始使用应用。
显示系统和应用进程如何相互移交工作:
reportFullyDrawn()主要作用:我们通常来说会使用异步懒加载的方式来提升程序画面的显示速度,这通常会导致的一个问题是,程序画面已经显示,可是内容却还在加载中。为了衡量这些异步加载资源所耗费的时间,我们可以在异步加载完毕之后调用 activity.reportFullyDrawn()方法来告诉系统此时的状态,以便获取整个加载的耗时。
从上图可以看到,整个冷启动流程中至少有两处onCreate
,分别是Application
和Activity
,整个流程都是可控的。所以,onCreate
方法做的事情越多,冷启动消耗的时间越长;
冷启动优化可以分为两部分,一个是解决黑屏白屏的问题,另一个就是解决APP启动时间过长问题;
第一种方式:
Android系统在启动APP的时候,会将第一个启动的Activity的背景拿出先展示出来,若Activity的window背景没有设置,那默认就是白屏;若设置了透明,就会点击后看起来没有反应。
第二种方式(推荐):
Android 为我们提供了 android:windowBackground 的解决方案,我们可以专门为 SplashActivity 设置一个背景来避免 创建空白(黑色) 窗口这一步骤的尴尬,而对于 android:windowBackground 又延伸了各种各样的方案。
假如启动页显示是一个视频,可以考虑把视频的第一帧做为android:windowBackground需要显示;
设置启动页样式
采用这种方式APP:网易新闻,今日头条,微博,知乎很多APP都是采用第二种方式,打开APP会显示android:windowBackground设置过度页面,然后在显示广告,广告可以跳过;
1)如何确认启动时间
要正确诊断启动时间性能,您可以跟踪一些显示应用启动所需时间的指标。
在 Android 4.4(API 级别 19)及更高版本中,logcat 包括一个输出行,其中包含名为 Displayed 的值。此值代表从启动进程到在屏幕上完成对应 Activity 绘制所经过的时间。经过的时间包括以下事件序列:
启动进程。
初始化对象。
创建并初始化 Activity。
扩充布局。
首次绘制应用。
报告的日志行类似于以下示例:
02-09 16:46:45.849 1661-1687/system_process I/ActivityManager: Displayed
com.github.baby.owspace/.view.activity.SplashAcitivty: +773ms
2)启动时间手动测试
先测量activity的启动时间:调用Activity的reportFullyDrawn()方法;
你就需要调用Activity的reportFullyDrawn()。它将在log里报告从apk初始化(和前面Displayed的时间是一样的)到reportFullyDrawn() 方法被调用用了多长时间;
reportFullyDrawn()方法显示的log也是类似这样(我们会发现时间是从apk初始化到点击按钮调用reportFullyDrawn()的方法的时间,同时reportFullyDrawn()方法只能调用一次输出日志):
I/ActivityManager: Fully drawn com.github.baby.owspace/.view.activity.fragments.FragmentManagerAcitivty:
+14s443ms
在4.4上调用reportFullyDrawn()方法会崩溃(但是log还是能正常打印),提示需要UPDATE_DEVICE_STATS权限 ,但是这个权限只有系统app才能授权。解决的办法是这样调:
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt_scroller_scroll:
mTextView.startScrollerScroll();
try{
if (Build.VERSION.SDK_INT >= 19) {
reportFullyDrawn();
}
}catch(SecurityException e){}
break;
}
}
分析我们的Application onCreate过程究竟做了哪些事情,哪些事情是必须的,哪些事情是可以移除的,哪些事情是可以分段处理的,分析我们的Splash到Main又经历了哪些事情;
1)Application中onCreate()优化:
a.延后处理,非必要在onCreate()初始化或执行的,不在onCreate()处理;
b.按需处理,实际需要创建的对象或资源在用到的时候处理;
c.别的一些细节点
如:启动过程可能会用到一些Utils等工具类,某些Utils类中定义了静态变量,这些静态变量的初始化有一定的耗时,可以把静态变量的初始化移到第一次使用的时候。这样可以避免在用到工具类的其他方法时提前做了没必要的初始化。
d.抓细节
冷启动的优化是个非常琐碎的事情,先把大头去掉,后面就是抠细节,细节处深挖,能节约一点时间算一点,蚂蚁小也是肉。
e.将一些需要初始化的工作放在IntentService处理
IntentService,可以看做是Service和HandlerThread的结合体,在完成了使命之后会自动停止,适合需要
在工作线程处理UI无关任务的场景。
温启动涵盖在冷启动期间发生的操作的一些子集;同时,它的开销比热启动多。有许多潜在状态可视为温启动。例如:
1)用户退出您的应用,但之后又重新启动。进程可能已继续运行,但应用必须通过调用 onCreate() 从头开始重新创建 Activity。
2)系统将您的应用从内存中逐出,然后用户又重新启动它。进程和 Activity 需要重启,但传递到 onCreate() 的已保存实例状态包对于完成此任务有一定助益。
将app
首页的按返回键响应修改为响应Home
键,曲线救国。让用户以为app
确实退出了,但是实际上是点了Home
键。如此一来,下次点击app
图标的时候,直接唤起,不需要进行初始化操作,主要可以避免再次走闪屏页,参考美团,微信,QQ,淘宝等(实现的效果一样,但是实现方式就不得而知了)
a.微博:启动后点击返回键和Home键的操作一样,底部选中tab没有做自切换
b.美团:启动后点击返回键和Home键的操作不一样,底部选中tab做了自切换
c.QQ:同微博
d.淘宝:启动后在首页按返回键,会先回到第一个tab,然后再退出
1)返回监听,不执行finish(),直接回到首页
@Override
public void onBackPressed() {
// super.onBackPressed();
Intent i = new Intent(Intent.ACTION_MAIN);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.addCategory(Intent.CATEGORY_HOME);
startActivity(i);
}
2)手动隐藏当前Activity;
在activity中有个moveTaskToBack(boolean isTask)方法:
参数说明:
参数为false——代表只有当前activity是task根,指应用启动的第一个activity时,才有效;
参数为true——则忽略这个限制,任何activity都可以有效。
说明:判断Activity是否是task根,Activity本身给出了相关方法:isTaskRoot()
这两种方法都是将activity 退到后台,注意不是finish()退出。
应用的热启动比冷启动简单得多,开销也更低。在热启动中,系统的所有工作就是将您的 Activity 带到前台。如果应用的所有 Activity 都还驻留在内存中,则应用可以无须重复对象初始化、布局扩充和呈现。
但是,如果一些内存为响应内存整理事件(如 onTrimMemory())而被完全清除,将需要重新创建这些对象,以响应热启动事件。
热启动显示的屏幕上行为和冷启动场景相同:系统进程显示空白屏幕,直到应用完成 Activity 呈现。
在冷启动完成以后可以在Activity回调方法执行相应操作例如播放广告或者延时关闭过度页面;
@Override
public void onWindowFocusChanged(boolean hasFocus) {
if (!hasFocus || animationStarted) {
return;
}
animate();
super.onWindowFocusChanged(hasFocus);
}
参考:
https://blog.csdn.net/u013381333/article/details/52925921
https://www.cnblogs.com/sharkchao/p/10326690.html
https://blog.csdn.net/jessicaiu/article/details/82147143
https://developer.android.com/topic/performance/launch-time.html