之前大家应该看过我写的启动流程分析了吧,那篇文章里我说过分析源码的目的一直都不是为了学知识而学,而是理解了这些基础,我们才能更好的解决问题。所以今天就来看看通过分析app启动流程,我们该怎么具体进行启动优化。
- App启动流程中我们能进行优化的地方有哪些?
- 具体有哪些优化方法?
- 分析启动耗时的方法
App启动流程中我们能进行优化的地方有哪些?
- Application的
attach
方法,MultiDexApplication会在方法里面会去执行MultiDex逻辑。 - Application的
onCreate
方法,大量三方库的初始化都在这里进行, - Activity的
onCreate、onStart、onResume
方法。
具体有哪些优化方法?
- 障眼法之闪屏页
为了消除启动时的白屏/黑屏,可以通过设置android:windowBackground
,让人感觉一点击icon就启动完毕了的感觉。
<activity android:name=".ui.activity.启动activity"
android:theme="@style/MyAppTheme"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<style name="MyAppTheme" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowBackground">@drawable/logo</item>
</style>
- 预创建Activity
对象第一次创建的时候,java虚拟机首先检查类对应的Class 对象
是否已经加载。如果没有加载,jvm会根据类名查找.class文件
,将其Class对象载入。同一个类第二次new的时候就不需要加载类对象,而是直接实例化,创建时间就缩短了。
- 第三方库懒加载
很多第三方开源库都说在Application
中进行初始化,所以可以把一些不是需要启动就初始化的三方库的初始化放到后面,按需初始化,这样就能让Application
变得更轻。
- WebView启动优化
webview
第一次启动会非常耗时,具体优化方法可以看我之前的文章,关于webview
的优化。
- 线程优化
线程是程序运行的基本单位,线程的频繁创建
是耗性能的,所以大家应该都会用线程池。单个cpu情况下,即使是开多个线程,同时也只有一个线程可以工作,所以线程池的大小要根据cpu个数来确定。
- MultiDex 优化
由于65536方法限制,所以一般class
文件要生成多个dex文件,Android5.0
以下,ClassLoader加载类的时候只会从class.dex(主dex)
里加载,所以要执行MultiDex.install(context)
方法才能正常读取dex类。
而这个install方法就是耗时大户,会解压apk,遍历dex文件,压缩dex、将dex文件通过反射转换成DexFile对象、反射替换数组。
这里需要的方案就是今日头条方案:
1、在Application的attachBaseContext
方法里,启动另一个进程的LoadDexActivity
去异步执行MultiDex逻辑,显示Loading。
2、然后主进程Application进入while循环,不断检测MultiDex
操作是否完成 3、MultiDex执行完之后主进程Application继续走,ContentProvider
初始化和Application onCreate
方法,也就是执行主进程正常的逻辑。
所以重点就是单开进程去执行MultiDex
逻辑,这样就不影响APP的启动了。
分析启动耗时的方法
- Systrace 函数插桩
也就是通过在方法的入口和出口加入统计代码,从而统计方法耗时
代码语言:javascript复制class Trace{
public static void i(String tag){
android.os.Trace.beginSection(tag);
}
public static void o(){
android.os.Trace.endSection();
}
}
void test(){
Trace.i("test");
System.out.println("doSomething");
Trace.o();
}
* BlockCanary
BlockCanary
可以监听主线程耗时的方法,就是在主线程消息循环打出日志的地入手, 当一个消息操作时间超过阀值后, 记录系统各种资源的状态, 并展示出来。所以我们将阈值设置低一点,这样的话如果一个方法执行时间超过200毫秒,获取堆栈信息。
而记录时间的方法我们之前也说过,就是通过looper()方法中循环去从MessageQueue
中去取msg的时候,在dispatchMessage方法前后会有logging日志打印,所以只需要自定义一个Printer
,重写println(String x)
方法即可实现耗时统计了。
参考文章
https://juejin.im/post/6844903958113157128
Android开发者们,快来关注公| 众 |号【码上积木】,每天三问面试题,并详细剖析,助你成为offer收割机。 相信积累的力量。