项目优化实战 —— App启动时间优化
一顿骚操作写完项目之后,运行一看炸裂了;在冷启动的时候,APP启动时间居然要十几秒,当遇到白屏或者黑屏的时候,更多的是想到了使用
background
的方式来替换刚刚启动时候的界面显示,但是这样通常是治标不治本的;因为使用background
的方式应用的启动时间是不变的,导致用户停留在闪屏页面时间过长,接下来我们来分析一下应用启动耗时
看完本篇文章你将了解到:
· 在`logcat`中查看界面启动时间
· 使用`adb`方式启动`Activity`查看耗时时间
· 使用`Debug`来追踪方法中函数耗时
· 使用`Android Studio`来查看`trace`文件,分析`trace`文件中耗时方法
· 优化应用启动时间
在logcat中查看应用启动时间
使用真机调试的时候,往往因为logcat打印太快而忽略了系统打印的一些信息,比如displayed
是用来记录Activity
的启动时间:
注意 画框 的地方: 选中自己调试的应用,在过滤输入框中输入 displayed 启动自己的调试的应用之后,将会看到如图中显示的打印时间; 可以看到,当前应用启动时间是非常久的,我使用该应用之后的第一个想法是卸载(摊手)
使用logcat查看可能觉得太low,不能展示我们装逼的格调,接下来我们使用adb
的方式启动应用:
使用adb shell命令的方式启动Activity查看启动时间
adb
是sdk platform-tools
中的一个工具,我们先将其添加到环境变量中,然后在终端调用adb
,可以看到一系列的命令; 我们这里不作命令的讲解,既然是要查看Activity
启动时间,而Activity
的启动都是由ActivityManager am
管理; 当我们在官网查看adb命令时,下面则对am
进行了讲解:
https://developer.android.com/studio/command-line/adb?hl=zh-cn#shellcommands
接下来我们使用 adb shell am
的方式启动Activity
:
可以看到总的启动时间为 3096 毫秒
, 在logcat中最后一次的SplashActivity
启动时间一样;上面使用了两种方法来查看应用启动到第一个界面的等待总时间,可以看到当点击应用图标时进入到页面花费了大量的时间,那这个时间做什么去了呢?
分析Application中 onCreate 耗时
点击应用图标启动到进入界面的这段逻辑中,系统做了大量的初始化操作,而这些操作我们是无法进行优化的,所以只能在onCreate()
方法中进行优化处理;
官网中对日志追踪有详细的介绍,这里不再赘述;我们直接使用
官网介绍:https://developer.android.com/studio/profile/generate-trace-logs?hl=zh-cn#instrument
假设在这里你已经看懂了使用Debug来追踪调试日志的方法,我们使用Debug.startMethodTracing(file.getAbsolutePath());
来告诉系统开始追踪方法,使用 Debug.stopMethodTracing()
停止追踪,两个方法之间就是你需要追踪调用时间的代码;
具体使用 :
@Override
public void onCreate() {
super.onCreate();
File file = new File(Environment.getExternalStorageDirectory(), "app");
Log.d("Debug ====", file.getAbsolutePath());
Debug.startMethodTracing(file.getAbsolutePath());
dbApplication = this;
// .... 省略实际代码
Debug.stopMethodTracing();
}
当然作为调试,这里没有做权限申请,你需要在应用启动之前设置允许该应用的存储权限;加入该代码之后,重新运行一次,你将在/storage/emulated/0
目录下看到 app.trace
文件,使用adb pull
命令将该文件导出:
接着将该文件拖动到android studio
中,接下来你将看到最新的Android studio
分析 trace
文件:
和之前的版本不同的是,最新版本的分析可以清楚的看到哪些调用耗时时间;在分析出的结果中,我们看到项目中使用的Mob分享和小米推送两个耗时最多,接下来我们将一个个优化,既然是第三方的sdk,最先考虑的是能不能将其放入到子线程
中和启动页面中,这样既避免了启动耗时,同样也不会影响后面的操作流程; 当然,有些第三方sdk需要使用到Handler
, 这样我们另做考虑; 接下来我们将优化其中的耗时调用,
优化第三方SDK
-
优化
mob sdk
我将MobSDK.init
放入到闪屏页面中的子线程中
// 使用Rxjava
Observable.just("").subscribeOn(Schedulers.io()).subscribe(s -> getModel().MobSDKInit());
一开始,我们是不知道第三方sdk是否能放入到子线程中的,所以,我们只能试探性的运行尝试,不行再尝试其他方法;修改完代码之后,我们再次Debug调试,重复Debug
Application
的 onCreate()
方法, 调出trace
文件查看结果:
调试之后,看到运行时间轴消耗时间,别吓到了,每次显示的是占用时间最长的,这里我们使用同样的方式优化接下来的第三方sdk;
-
优化
mi push sdk
我们将小米推送放入到闪屏的子线程中,看到trace文件中没有了耗时,而且要用正常执行,没有报错:
优化小米推送之后.png
接下来,我们看到一长条的FeedbackApi
这是阿里的反馈初始化,优化它
-
优化
ali feedback sdk
按照如上的操作,我相信同学们应该都会优化了;将所有的优化进行完之后,我们看下启动时间:
最后启动时间.png
上面详细讲解了从启动时间的获取到第三方sdk
的优化,当然我这里都是在子线程执行,因为大部分第三方的sdk
不涉及到Handler的使用,但是不可避免的是会遇到;下面就有这种情况,当使用腾讯的IM的时候,使用到了Handler,所以在这里建议使用IntentService
,关于IntentService
使用,大家自行谷歌吧~
总结
到最后, 应该都懂得了启动优化,不再简单的使用
background
的方式来填充了,应该找到根本原因~优化主要分为:
Debug.startMethodTrace
开始Trace
Debug.stopMethodTrace
结束Trace
- 获取到
trace
文件- 分析方法中耗时调用
- 优化