Open zhjlong opened 5 years ago
一、应用的启动方式
通常来说,启动方式分为两种:冷启动和热启动。
1、冷启动:当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用,这个启动方式就是冷启动。
2、热启动:当启动应用时,后台已有该应用的进程(例:按back键、home键,应用虽然会退出,但是该应用的进程是依然会保留在后台,可进入任务列表查看),所以在已有进程的情况下,这种启动会从已有的进程中来启动应用,这个方式叫热启动。
特点
1、冷启动:冷启动因为系统会重新创建一个新的进程分配给它,所以会先创建和初始化Application类,再创建和初始化MainActivity类(包括一系列的测量、布局、绘制),最后显示在界面上。
2、热启动:热启动因为会从已有的进程中来启动,所以热启动就不会走Application这步了,而是直接走MainActivity(包括一系列的测量、布局、绘制),所以热启动的过程只需要创建和初始化一个MainActivity就行了,而不必创建和初始化Application,
因为一个应用从新进程的创建到进程的销毁,Application只会初始化一次。
Android冷启动时间优化
冷启动时间是指当用户点击你的app那一刻到系统调用Activity.onCreate()之间的时间段。在这个时间段内,WindowManager会先加载app主题样式中的windowBackground做为app的预览元素,然后再真正去加载activity的layout布局
冷启动时间优化 知道了Android冷启动时间的原理之后,就可以通过一些小技巧来对冷启动时间进行优化,从而让你app加载变得”快“一些(视觉体验上的快。
Skylar同学提到,要进行启动优化,首先要定位问题,那怎么才能定位问题呢?
一般是使用两个工具来定位,一是traceview,在代码要检测的代码部分startTrace和stopTrace,然后查看trace文件进行分析;二是使用systrace脚本进行分析;
我必须要说的是,首先startTrace和stopTrace必须成对使用,才能生成trace跟踪文件;其次,改方法只适合线下使用,因为记录各种运行信息的同时会拖慢程序运行的速度;第三,可能会把小问题扩大化,引向错误的优化方向。
其实我们可优化的点很有限,一是application的启动耗时,而是mainActivty的启动耗时。 针对一,一般是因为application中执行了太多的任务,我们可以使用异步优化的思路来减少阻塞执行的耗时;针对某些有依赖关系的任务,还可以使用countdownLaunch来进行阻塞等待异步任务完成再往下执行。
针对二,可能导致的原因,一是布局复杂导致的加载阻塞耗时,这个可以通过布局异步加载来缓解,具体可以看我的博客异步加载布局探索。二是启动时出发的生命周期中执行了太多的任务,可以适当的进行延迟初始化。
学习本课题重点偏实践,尤其是工具使用.以及具体问题分析,本课题大概会花费我两天时间总结.先列个大纲,后续慢慢填充.你是否遇到过以下问题
如果有,希望以下大纲能够帮助到你,有问题一块儿探讨~
热启动是指,当前应用还在,如(触发Home,该应用仍然保留在后台)从已有进程启动应用,这种方式叫热启动,直接执行Application
和Activity
生命周期和进行ViewRootImpl
布局绘制.
冷启动耗时最多,衡量标准:
首先触发点击事件 ,进入我们程序的IPC
机制,通过IPC
机制执行我们的Process.java
的 start
方法.然后在执行我们的ActivityThread
的main
方法,继续bindApplication
创建我们的Application
,然后在初始化我们的页面响应Activity
生命周期.生命周期结束后,再执行ViewRootImpl
进行布局结束.这就是整个冷启动的启动流程,整个过程在于fork进程
和Application
创建或Activty
布局渲染导致时间开销过大.
Application
和 Activty
以及 进程优化
adb shell am start -W packagename/首屏Activity
手动打点
记录启动时间和终止时间,attachBaseContext
记录启动时间,不要在onwindowFocus
首帧记录终止时间,而是在View
第一次绘制的时候记录.然后用Log打印,当然,Log打印也不是完美的,因为Log打印有时间差,推荐采用函数插桩
方式.
函数插桩
systrace
说明环境搭建成功了~
sharePrefrence
存储过程中不要在异步线程使用apply(),线程不安全.
懒加载,和启动无关的业务模块学会迁移到其他页面
SplashActivty
和MainActivity
合二为一,但是相关逻辑要进行特殊判断,逻辑处理相对复杂,不推荐
在启动过程不要做有关系统调度情况,如:Binder
调用等待,PMS
操作等.
我们要注意这些线程是否有阻塞情况.数据超过100kb
,sp
保存数据异步线程可以用commit()
,onPause
,sp
会强制磁盘未落地,如果读写操作未完成会造成卡顿ANR
,如需保存大的数据,可以考虑MMKV
替代sp
或者考虑在Application
重写getSharePrefrence()
方法.
Hook
手段 免除 verify class
步骤 保活可以减低你的Application
创建和初始化时间,让冷启动变为温启动,不过在Android7.0
阉割了某些广播属性,保活越来越难.
Tinker
框架在加载补丁后,应用启动速度会降低 5%~10%,360加固也会降低启动时间,所以我们在使用的时候,需要做出一些权衡和选择.
Application启动优化: 1、布局优化 我们的启动页Activity包含有启动图控件、闪屏广告图控件、闪屏广告视频控件、首次安装介绍图控件。对于布局优化而言,除了启动图控件外,其他都不是App启动时都要初始化的控件,这时我们可以使用ViewStub。针对指定的业务场景,初始化指定的控件。 2、避免I/O操作 我们知道I/O操作不是实时的,例如数据库的读写、SharedPreferences#apply()。我们要注意这些操作有没阻塞主线程地执行,同时我们可以利用StrictMode严格模式,利用它可以检测我们在启动的时候有没正确进行磁盘读写操作。 3、注意图片bitmap的加载速度和编码格式 我们可以知道,启动页大部分的情况下都是图片的显示,那么我们在图片这方面怎么抠细节呢,那就是对各种第三方图片加载库的选用了Glide、Picasso、Fresco等,还有是PREFER_ARGB_8888、PREFER_RGB_565的选取问题,大家可以针对属于自己项目情况进行选取。 4、对矢量图VectorDrawable对象的使用 矢量图的核心是省时间、省空间。而对于某些用户,它的启动图可能不是一张图片,它十分简约,就一个logo,这个时候我们可以考虑一下矢量图的用法。 5、注意Activity中的启动生命周期的回调 我们在Application#onCreate()优化,将某些不是很必要的网络请求,搬到了欢迎页中,但是我们也不能直接将这个网络请求操作直接拷贝到启动页的onCreate()中,我们可以巧妙地利用Activity生命周期中的Activity#onWindowFocusChanged(boolean hasFocus) ,这个是所有控件初始化完的真正回调,我们可以将网络操作放在这里,当然我们还可以使用Service。
放上我参考的文章: Android 性能优化(一) —— 启动优化提升60% Android:手把手教你如何优雅的实现APP启动速度优化
启动优化应该可以分两大类:一类视觉优化,一类逻辑优化。 上一个问题是说出你理解的程序启动过程,我们要优化的就是从点击app图标到页面展示这一段。
在应用启动的过程中,在应用程序启动后立刻会展示启动窗口,这也就是我们后边进行视觉优化的地方,展示启动窗口的同时我们会在后台准备创建应用程序的创建。
视觉优化
对启动主题进行操作 1.把启动主题设置成透明
<!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="android:windowFullscreen">true</item> <item name="android:windowIsTranslucent">true</item> </style>
这样操作,我们点击app图标之后回有短暂的停留然后进入应用的首页,这还是会有体验上的不快。 2.把启动主题设置成一张图片
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:windowBackground">@drawable/lunch</item> //闪屏页图片 <item name="android:windowFullscreen">true</item> <item name="android:windowDrawsSystemBarBackgrounds">false</item><!--显示虚拟按键,并腾出空间--> </style>
这样点击app图标之后,立即会展示一张图片,短暂停留之后进入应用首页。这样的体验会比透明的主题要好。
从进程被创建到执行Activity的onWindowFocusChanged()这段时间是我们要进行优化的区域。 这里大概写一些优化的方面 1.Application的优化
一、启动分类
二、优化思路
作为普通应用,App进程的创建等环节我们是无法主动控制的。开发人员唯一能做的就是在Application 和 第一个 Activity 中,减少 onCreate() 方法的工作量,从而缩短冷启动的时间。像应用中嵌入的一些第三方 SDK,都建议在 Application 中做一些初始化工作,开发人员不妨采取懒加载的形式移除这部分代码,而在真正需要用到第三方 SDK 时再进行初始化。
Google也给出了启动加速的方向:
三、优化方案
1.主题切换
2.避免Application的onCreate进行太多的工作
对onCreate中的初始化工作进行异步加载、延时加载、懒加载。
3.避免首个Activity的onCreate进行太多的工作
使用延迟加载。确保在Activity的页面显示出来之后再进行加载数据,避免过早或过晚的加载导致页面空白时间过长。
4.MultiDex初次启动优化
5.0以下某些低端机会出现ANR或者长时间卡顿不进入引导页,而罪魁祸首是MultiDex.install(Context context)的dexopt过程耗时过长。
解决思路