在开发车机系统过程中,为了解决SystemUI、Launcher启动时间延迟导致窗口空白影响用户体验问题必须找出各个模块启动时间,才能方便后续进行分析、优化。
博主在负责的车机系统SystemUI开发过程中,为了准确计算出SystemUI界面 显示出来所需要的时间进行了如下思考:
第一:SystemUI 不同于其他应用,该模块内没有Activity组件,从计算系统加载SystemUI 模块到页面呈现在用户面前就不能借助Activity的生命周期回调
第二:为了计算系统加载SystemUI 到该模块内两个主要的视图(导航栏、状态栏)显示出来需要编写一个工具,在系统加载SystemUI模块时开始计算时间,到导航栏、状态栏 视图显示出来计算出所需要的时间。
第三:系统加载到SystemUI时根据那个状态来进行开始计算呢?考虑到系统加载SystemUI应用时会首先执行 Application 的 attachBaseContext方法,该方法执行的顺序先于onCreate 方法,就在此开始计算时间。开始计算时间的点找到了,下一步在哪儿埋点获取启动SystemUI 所消耗的时间呢?找到了其中承载导航栏业务的CarNavigationBarView 组件,在该View中的onWindowVisibilityChanged 方法中计算时间差,算出总的所需时间。选择该方法中也是考虑到该视图显示出来后会回调这个方法,视图显示出来就会认为SystemUI 显示出来了。
上面对问题进行了分析,下面贴出计算时间差的工具代码:
package com.android.systemui.util;
import java.util.HashMap;
/**
* @ProjectName: SystemUI-v0.1
* @Package: com.android.systemui.util
* @ClassName: TimeUtils
* @Description: 计时统计工具类
* @Author: Yw
* @CreateDate: 22-1-20 下午3:26
* @Version: 1.0
*/
public class TimeUtils {
private static HashMap<String, Long> sCalTimeMap = new HashMap<>();
public static final String COLD_START = "cold_start";
public static final String HOT_START = "hot_start";
public static long sColdStartTime = 0;
/**
* 记录某个事件的开始时间
*
* @param key 事件名称
*/
public static void beginTimeCalculate(String key) {
long currentTime = System.currentTimeMillis();
sCalTimeMap.put(key, currentTime);
}
/**
* 获取某个事件的运行时间
*
* @param key 事件名称
* @return 返回某个事件的运行时间,调用这个方法之前没有调用 {@link #beginTimeCalculate(String)} 则返回-1
*/
public static long getTimeCalculate(String key) {
long currentTime = System.currentTimeMillis();
Long beginTime = sCalTimeMap.get(key);
if (beginTime == null) {
return -1;
} else {
sCalTimeMap.remove(key);
return currentTime - beginTime;
}
}
/**
* 清除某个时间运行时间计时
*
* @param key 事件名称
*/
public static void clearTimeCalculate(String key) {
sCalTimeMap.remove(key);
}
/**
* 清除启动时间计时
*/
public static void clearStartTimeCalculate() {
clearTimeCalculate(HOT_START);
clearTimeCalculate(COLD_START);
sColdStartTime = 0;
}
}
在SystemUIApplication的attachBaseContext方法中
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
Log.d(TAG, "attachBaseContext ---Time :" + System.currentTimeMillis());
TimeUtils.beginTimeCalculate(TimeUtils.COLD_START);
}
在导航栏View视图CarNavigationBarView onWindowVisibilityChanged方法中
@Override
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
long hotStartTime = TimeUtils.getTimeCalculate(TimeUtils.HOT_START);
long timeColdCalculate = TimeUtils.getTimeCalculate(TimeUtils.COLD_START);
Log.d("CarNavigationBarView", "onWindowVisibilityChanged ---hotStartTime :" + hotStartTime + ",timeColdCalculate :" + timeColdCalculate);
}
变异好应用重新推到车机系统内层,找出SystemUI进程名,kill掉老进程让系统重新加载变异的APK 查询到的时间如下:
上面是kill掉SystemUI 进程系统后,重新加载所需的时间。考虑到实际用户情况不存在kill掉的场景,将按住mode按键重启后发现启动时间:
总结:目前大致计算出SystemUI 启动时间,但是具体时间消耗不是很明确,后续将完善补充分析过程,找出问题、解决问题。