1.Launcher 耗时大方向优化

1.1 IO 优化

MyApplication 和 LauncherActivity Oncreate () 中 IO 操作判断哪些是必须的,非必须的,使用子线程或者延后加载。默认启动 VPA 界面,可以先将布局加载出来之后,然后通知退出开机动画,使用 IdleHandle 加载资源显示具体的资源内容。

1.2 懒加载或者初始化时机

Launcher 有三个 Fragment:MapFragment、VpaFragment 和 CarFragment。默认启动的 VpaFragment,其他两个 Fragment 不显示,相关资源不要在启动界面加载。

1.3 找退出开机动画的时机

由于当前项目开机动画由 QNX 来控制,Android 原生开机动画被 QNX 图层覆盖,因此 Launcher 需要找退出开机动画的时机,以保证用户尽早看到 Launcher 主界面。

2.MyApplication 耗时分析

2.1 initConfig();

initConfig.png

initConfig.png

初始化配置耗费 470ms, 其中加载 so 库耗时 231ms, 初始化资源花费 212ms.

此部分主要涉及 IO 操作:

建议:

  • so 库如果属于 VPA 不相关的库,延迟加载该库。
  • initRes () 方法中有大量地图相关的配置文件和资源加载,尽量延后到 VPA 启动之后或者在加载 MapFragment 的时候在初始化这部分资源。
2.2 TtsPlayManager.init(this);

TtsPlayManager.png

TtsPlayManager.png

TtsPlayManager 的初始化方法主要实现了初始 speaker 和初始化 naviTts.

其中初始 speaker 消耗 8.6ms, 初始化 navi Tts 消耗 70.2ms.

建议:

  • navi Tts 初始化推迟加载
2.3 CommonUtil.initLayerStyle();

initLayerStyle.png

initLayerStyle.png

存解析 json 配置文件,消耗 42ms.

建议:

  • 如果和地图相关的初始化是否可以和地图初始化放一起。
2.4 FontsOverrideUtil.setDefaultFont();

设置字体.png

设置字体.png

加载三类字体,每个耗时 17ms 左右

建议:

  • 此处只是列出耗时,如果却有必要,可不优化。

3. LauncherActivity 耗时分析

3.1 加载布局文件

加载view.png

加载 view.png

主界面加载布局文件消耗 41ms。此处看加载布局文件耗时不算多,确实需要优化可以考虑使用异步加载布局。

建议:

  • 异步加载布局
java
1
2
3
4
5
6
7
8
9
10
11
12
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

new AsyncLayoutInflater(this).inflate(R.layout.activity_main, null, new AsyncLayoutInflater.OnInflateFinishedListener() {
@Override
public void onInflateFinished(@NonNull View view, int resid, @Nullable ViewGroup parent) {
setContentView(view);
}
});
.....
}
  • 注意此处或者当 VPA fragment 加载完成之后考虑一下是否可以通知开机动画退出?内容的展示后面加载出来在更新。
3.2 自定义 viewpage 耗时

自定义ViewPage加载布局耗时.png

自定义 ViewPage 加载布局耗时.png

从图中可以看到自定义 ViewPage 在测量阶段耗时 1.36s。(后面细化分析每个 fragment 启动耗时)

从下面细化调用栈看,ViewPage 中有加载三个 fragment:MapFragment、VpaFragment 和 CarFragment。

3.2.1 VPA Fragment 加载耗时

VPA fragment 由两部分内容构成,如下:

vpafragment1.png

vpafragment1.png

第一部分加载布局耗时 115ms。

vpafragment2.png

vpafragment2.png

第二部分加载布局耗时 110ms。

看了代码以上两部分耗时主要是加载布局文件耗时,可以暂时不优化。

3.2.2 MapFragment 加载耗时

map fragment.png

map fragment.png

从上图中可以看到 map fragment 加载耗时 840ms, 其中初始化消耗 103ms, 加载显示地图资源 (showMap ()) 消耗 736ms。

在 showMap () 方法中主要完成两部分工作:初始化 view (101ms) 和初始化地图资源 (635ms)。

3.2.3 CarFragment 加载耗时

CarFragment.png

CarFragment.png

从图中可以看出 CarFragment 主要完成的是布局加载,可以暂时不优化。

3.2.4 fragment 加载总结

结合当前交付场景:Launcher 启动之后只需要展示 VPA Fragment,因此需要 FO 实现 viewpage 懒加载机制。

我看当前代码是自定义 viewgroup 来实现的 viewpage,是否可以直接使用 viewpage2 自带懒加载效果,或者结合 viewpage+fragment,利用 setUserVisibleHint (boolean isvisible) 和 isViewCreated () 来实现懒加载效果。

从上面分析看,如果只加载 VPA Fragment, 不加载 MapFragment 和 Car Fragment,应该至少可以优化 1s 以上的启动耗时。

4. 通知 QNX 退出开机动画

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// com.gxatek.cockpit.launcher.LauncherActivity
@Override
protected void onStart() {
super.onStart();
Logger.d(TAG, "onStart, CarPowerManager.connect()");
mPower = CarPowerManager.getInstance(getApplicationContext(), carPowerEventListener);
mPower.connect();
if (curIndex == 0) {
((MapFragment) currentFragment).showMap();
}
}

CarPowerEventListener carPowerEventListener = new CarPowerEventListener() {
......

@Override
public void onCarPowerServiceConnected() {
Logger.d(TAG, "CarPowerManager onCarPowerServiceConnected, CarPowerManager.exitAnimationReq");
mPower.exitAnimationReq();
}

....
};

从上面代码可以看出,Launcher 通知开机动画退出的时机是:当所有布局和资源加载完成 (onCreate ()) 之后,再去绑定 CarPower 服务,绑定成功之后通知 qnx 退出开机动画。

正常情况下绑定服务也会耗时 200-300ms。

因此在此环节的优化建议:

  • 在 onCreate () 中加载完布局之后就绑定 CarPower 服务
  • 当 VPA Fragment 布局加载完成之后就通知 QNX 退出开机动画。

5. 其他优化建议

5.1 Arouter 插件优化

我看项目代码中有用到 Arouter 插件,可以在项目中集成 Arouter Gradle 插件来实现自动注册功能。

arouter优化.png

arouter 优化.png

5.2 EventBus Apt 优化

EventBus 3.0 之前的版本是没有索引的,检索订阅方法是通过反射获取的。我们都知道反射的效率令人堪忧,如果频繁地调用的话,肯定会对程序的性能造成影响。而 greenrobot 也意识到这个问题,所以在 EventBus 3.0 版本新增一个索引的功能,它主要是通过在编译期处理,生成订阅者和订阅方法的对应关系并缓存起来,从而在程序运行时能快速索引。

eventbus优化.png

eventbus 优化.png

5.3 SharedPreference 优化

如果启动时加载的 sharedpreference 过大,可以拆分 sharedpreference,将启动需要的配置分成一个 sharedpreference,不相关的配置分成另一个 sharedpreference。降低启动依赖配置文件的加载和解析时间。

参考文档:

1.《你知道 android 的 MessageQueue.IdleHandler 吗?》

2.《alibaba/ARouter: A framework for assisting in the renovation of Android componentization (帮助 Android App 进行组件化改造的路由框架) (github.com)》

3.《EventBus 源码详解(二):进阶使用 》