窗体的布局结构:
窗体布局层次:
窗体绘制:
上图中是表明DecorView的加载耗时:31.89ms
LauncherApplication的onCreate方法:
03-06 15:18:55.651 14699-14699/com.xtc.i3launcher D/LaunchComputer: start launch compute
03-06 15:18:55.771 14699-14699/com.xtc.i3launcher I/LaunchComputer: initDialData [119] ms
03-06 15:18:55.772 14699-14699/com.xtc.i3launcher I/LaunchComputer: CommonInit.init [120] ms
03-06 15:18:55.779 14699-14699/com.xtc.i3launcher I/LaunchComputer: FrescoUtil.init [127] ms
03-06 15:18:55.793 14699-14699/com.xtc.i3launcher I/LaunchComputer: LauncherDbManager.getInstance().init [142] ms
03-06 15:18:55.803 14699-14699/com.xtc.i3launcher I/LaunchComputer: DownloadAppDbManager.getInstance().init [151] ms
03-06 15:18:55.808 14699-14699/com.xtc.i3launcher I/LaunchComputer: InitServiceDbManager.getInstance().init [157] ms
03-06 15:18:55.830 14699-14699/com.xtc.i3launcher I/LaunchComputer: ChatDbManager.getInstance().init [178] ms
03-06 15:18:55.832 14699-14699/com.xtc.i3launcher I/LaunchComputer: ContactDbManager.getInstance().init [181] ms
03-06 15:18:55.853 14699-14699/com.xtc.i3launcher I/LaunchComputer: GradeDbManager.getInstance().init [201] ms
03-06 15:18:55.858 14699-14699/com.xtc.i3launcher I/LaunchComputer: LocationDbManager.getInstance().init [207] ms
03-06 15:18:55.931 14699-14699/com.xtc.i3launcher I/LaunchComputer: 权限设置 [280] ms
03-06 15:18:55.968 14699-14699/com.xtc.i3launcher I/LaunchComputer: initNeedNet [316] ms
03-06 15:18:55.976 14699-14699/com.xtc.i3launcher I/LaunchComputer: initMsgTypeInfo [324] ms
03-06 15:18:56.187 14699-14699/com.xtc.i3launcher I/LaunchComputer: ContactApp.init [536] ms
03-06 15:18:56.233 14699-14699/com.xtc.i3launcher I/LaunchComputer: WeiChatApp.init [581] ms
03-06 15:18:56.471 14699-14699/com.xtc.i3launcher I/LaunchComputer: MonitorBehavior.burryBootScene [819] ms
03-06 15:18:56.472 14699-14699/com.xtc.i3launcher I/LaunchComputer: finish LauncherApplication.onCreate [821] ms
HomeActivity.onCreate:
03-06 15:18:57.856 14699-14699/com.xtc.i3launcher I/LaunchComputer: before setContentView for HomeActivity [2204] ms
03-06 15:19:00.080 14699-14699/com.xtc.i3launcher I/LaunchComputer: setContentView for HomeActivity [4429] ms
03-06 15:19:00.098 14699-14699/com.xtc.i3launcher I/LaunchComputer: SharedTool.saveOneTrafficBytes [4447] ms
03-06 15:19:00.112 14699-14699/com.xtc.i3launcher I/LaunchComputer: HomeActivity.initData [4460] ms
03-06 15:19:00.113 14699-14699/com.xtc.i3launcher I/LaunchComputer: HomeActivity.initAnimation [4461] ms
03-06 15:19:00.125 14699-14699/com.xtc.i3launcher I/LaunchComputer: HomeActivity.initView [4473] ms
03-06 15:19:00.128 14699-14699/com.xtc.i3launcher I/LaunchComputer: HomeActivity.initFragment [4476] ms
03-06 15:19:00.134 14699-14699/com.xtc.i3launcher I/LaunchComputer: HomeActivity.initWatchLoss [4483] ms
03-06 15:19:00.556 14699-14699/com.xtc.i3launcher I/LaunchComputer: HomeActivity.initClassMode [4905] ms
03-06 15:19:00.588 14699-14699/com.xtc.i3launcher I/LaunchComputer: HomeActivity.initPowerSave [4935] ms
03-06 15:19:00.846 14699-14699/com.xtc.i3launcher I/LaunchComputer: HomeActivity.initTheme [5195] ms
03-06 15:19:01.043 14699-14699/com.xtc.i3launcher I/LaunchComputer: HomeActivity.startWakeLock [5392] ms
03-06 15:19:02.095 14699-14699/com.xtc.i3launcher I/LaunchComputer: HomeActivity.initOther [6443] ms
03-06 15:19:02.162 14699-14699/com.xtc.i3launcher I/LaunchComputer: SystemBehavior.behaviorSystemInfo [6511] ms
03-06 15:19:02.164 14699-14699/com.xtc.i3launcher I/LaunchComputer: ShellUtil.systemShutdownOrAppCrashBehavior [6513] ms
03-06 15:19:02.187 14699-14699/com.xtc.i3launcher I/LaunchComputer: HomeActivity.showLoadingImage [6536] ms
03-06 15:19:02.187 14699-14699/com.xtc.i3launcher I/LaunchComputer: finish HomeActivity.onCreate [6536] ms
HomeActivity.onResume:
03-06 15:19:02.198 14699-14699/com.xtc.i3launcher I/LaunchComputer: before HomeActivity.onResume [6547] ms
03-06 15:19:02.204 14699-14699/com.xtc.i3launcher I/LaunchComputer: HomeActivity.onResume [6553] ms
03-06 15:19:02.210 14699-14699/com.xtc.i3launcher I/LaunchComputer: finish HomeActivity.onResume [6559] ms
03-06 15:19:02.310 14699-14699/com.xtc.i3launcher I/LaunchComputer: before HomeActivity.onResume [6659] ms
03-06 15:19:02.314 14699-14699/com.xtc.i3launcher I/LaunchComputer: HomeActivity.onResume [6662] ms
03-06 15:19:02.320 14699-14699/com.xtc.i3launcher I/LaunchComputer: finish HomeActivity.onResume [6669] ms
HomeActivity.onWindowFocusChanged:
03-06 15:19:17.676 14699-14699/com.xtc.i3launcher I/LaunchComputer: onWindowFocusChanged [22024] ms
所以Launcher的大部分启动耗时就花在onResume到onWindowFocusChanged这里,有效的优化点为onCreate方法和onResume到onWindowFocusChanged
这是我用一个空的TestHomeActivity来替换HomeActivity的测试结果:
03-06 17:36:22.881 2613-2613/com.xtc.i3launcher D/LaunchComputer: start launch compute
03-06 17:36:22.983 2613-2613/com.xtc.i3launcher I/LaunchComputer: initDialData [102] ms
03-06 17:36:22.984 2613-2613/com.xtc.i3launcher I/LaunchComputer: CommonInit.init [103] ms
03-06 17:36:22.986 2613-2613/com.xtc.i3launcher I/LaunchComputer: FrescoUtil.init [105] ms
03-06 17:36:23.004 2613-2613/com.xtc.i3launcher I/LaunchComputer: LauncherDbManager.getInstance().init [123] ms
03-06 17:36:23.009 2613-2613/com.xtc.i3launcher I/LaunchComputer: DownloadAppDbManager.getInstance().init [129] ms
03-06 17:36:23.015 2613-2613/com.xtc.i3launcher I/LaunchComputer: InitServiceDbManager.getInstance().init [134] ms
03-06 17:36:23.092 2613-2613/com.xtc.i3launcher I/LaunchComputer: ChatDbManager.getInstance().init [211] ms
03-06 17:36:23.094 2613-2613/com.xtc.i3launcher I/LaunchComputer: ContactDbManager.getInstance().init [213] ms
03-06 17:36:23.123 2613-2613/com.xtc.i3launcher I/LaunchComputer: GradeDbManager.getInstance().init [243] ms
03-06 17:36:23.136 2613-2613/com.xtc.i3launcher I/LaunchComputer: LocationDbManager.getInstance().init [255] ms
03-06 17:36:23.183 2613-2613/com.xtc.i3launcher I/LaunchComputer: 权限设置 [302] ms
03-06 17:36:23.509 2613-2613/com.xtc.i3launcher I/LaunchComputer: initNeedNet [628] ms
03-06 17:36:23.523 2613-2613/com.xtc.i3launcher I/LaunchComputer: initMsgTypeInfo [642] ms
03-06 17:36:23.759 2613-2613/com.xtc.i3launcher I/LaunchComputer: ContactApp.init [878] ms
03-06 17:36:23.807 2613-2613/com.xtc.i3launcher I/LaunchComputer: WeiChatApp.init [926] ms
03-06 17:36:23.883 2613-2613/com.xtc.i3launcher I/LaunchComputer: MonitorBehavior.burryBootScene [1002] ms
03-06 17:36:23.884 2613-2613/com.xtc.i3launcher I/LaunchComputer: finish LauncherApplication.onCreate [1004] ms
03-06 17:36:25.128 2613-2613/com.xtc.i3launcher I/LaunchComputer: TestHomeActivity.onCreate [2248] ms
03-06 17:36:25.137 2613-2613/com.xtc.i3launcher I/LaunchComputer: TestHomeActivity.onResume [2256] ms
03-06 17:36:28.341 2613-2613/com.xtc.i3launcher I/LaunchComputer: TestHomeActivity.onWindowFocusChanged [5460] ms
修改前:原先在onCreate中执行了太多任务
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DisplayUtil.isCreate = true;
startMainCreateTimeMillis = SystemClock.elapsedRealtime();
setContentView(R.layout.activity_home);
ivFirstLoading = (ImageView) findViewById(R.id.iv_first_loading);
LogUtil.d("onCreate width = " + ScreenUtils.getScreenWidth(this) +
"---height = " + ScreenUtils.getScreenHeight(this));
EventBus.getDefault().register(this);
homeContainer = (ContainerView) findViewById(R.id.container_view);
vpMain = (ForbidScrollViewPager) findViewById(R.id.vp_main);
SharedTool.saveOneTrafficBytes(this, 0); // 开机启动流量置0,为了后面的流量统计提供使用
initData();
initAnimation();
initView();
initFragment();
presenter.registerCallReceiver();
initWatchLoss();
initClassMode();
initPowerSave();
initTheme();
presenter.startTimeChangeAlarm();
presenter.registerNotificationListenerService(this);
presenter.setScreenListener(screenListener);
presenter.setSimStateCallback(simStateCallback);
presenter.setClockChangeListener(clockChangeListener);
CloudMusicReceiver.getInstance().registerReceiver(this);
vibrateHelper = VibrateHelper.getInstance(this);
batteryHelper = BatteryHelper.getInstance(this);
DisplayUtil.startWakeLock(this, false);
initOther();
//埋点系统信息
SystemBehavior.behaviorSystemInfo();
ShellUtil.systemShutdownOrAppCrashBehavior(this);
showLoadingImage();
}
修改后:把不需要在onCreate中执行的任务放到onWindowFocusChanged第一次获取焦点的时候再去执行,因为这时候界面已经可见,界面可见后再去加载一些数据信息就不会影响到界面启动的速度了
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DisplayUtil.isCreate = true;
startMainCreateTimeMillis = SystemClock.elapsedRealtime();
LaunchComputer.trace("before setContentView for HomeActivity");
setContentView(R.layout.activity_home); // TODO: 2018/3/6 耗时
LaunchComputer.trace("setContentView for HomeActivity");
// ivFirstLoading = (ImageView) findViewById(R.id.iv_first_loading);
LogUtil.d("onCreate width = " + ScreenUtils.getScreenWidth(this) +
"---height = " + ScreenUtils.getScreenHeight(this));
EventBus.getDefault().register(this);
homeContainer = (ContainerView) findViewById(R.id.container_view);
vpMain = (ForbidScrollViewPager) findViewById(R.id.vp_main);
SharedTool.saveOneTrafficBytes(this, 0); // 开机启动流量置0,为了后面的流量统计提供使用
LaunchComputer.trace("SharedTool.saveOneTrafficBytes");
initData();
LaunchComputer.trace("HomeActivity.initData");
initAnimation();
LaunchComputer.trace("HomeActivity.initAnimation");
initView();
LaunchComputer.trace("HomeActivity.initView");
/*initFragment();
LaunchComputer.trace("HomeActivity.initFragment");*/
// presenter.registerCallReceiver();
/*initWatchLoss();
LaunchComputer.trace("HomeActivity.initWatchLoss");*/
/*initClassMode(); // TODO: 2018/3/6 耗时
LaunchComputer.trace("HomeActivity.initClassMode");
initPowerSave(); // TODO: 2018/3/6 耗时
LaunchComputer.trace("HomeActivity.initPowerSave");
initTheme(); // TODO: 2018/3/6 耗时
LaunchComputer.trace("HomeActivity.initTheme");*/
/*presenter.startTimeChangeAlarm();
presenter.registerNotificationListenerService(this);
presenter.setScreenListener(screenListener);
presenter.setSimStateCallback(simStateCallback);
presenter.setClockChangeListener(clockChangeListener);*/
CloudMusicReceiver.getInstance().registerReceiver(this);
// vibrateHelper = VibrateHelper.getInstance(this);
// batteryHelper = BatteryHelper.getInstance(this);
DisplayUtil.startWakeLock(this, false);
LaunchComputer.trace("HomeActivity.startWakeLock");
/*initOther();
LaunchComputer.trace("HomeActivity.initOther");*/
//埋点系统信息
/*SystemBehavior.behaviorSystemInfo(); // TODO: 2018/3/6 耗时
LaunchComputer.trace("SystemBehavior.behaviorSystemInfo");
ShellUtil.systemShutdownOrAppCrashBehavior(this);
LaunchComputer.trace("ShellUtil.systemShutdownOrAppCrashBehavior");*/
showLoadingImage();
LaunchComputer.trace("HomeActivity.showLoadingImage");
LaunchComputer.trace("finish HomeActivity.onCreate");
}
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
LogUtil.i("wtx hasFocus" + hasFocus);
if (hasFocus && !firstInit) {
firstInit = true;
LaunchComputer.trace("onWindowFocusChanged");
windowFocused();
}
if (!hasFocus) {
DisplayUtil.setNormalScreenOffTimeout(this);
setHasSetTime(false);
} else {
setTimeOnClock();
}
startCostTimeBehavior();
}
private void windowFocused() {
// 开机速度优化:把一些无需马上执行的操作放到这里执行
initFragment();
initWatchLoss();
initClassMode();
initPowerSave();
initTheme();
initForPresenter();
initOther();
SystemBehavior.behaviorSystemInfo();
ShellUtil.systemShutdownOrAppCrashBehavior(this);
SyncData.launcher(getApplicationContext());
}
修改前:
在HomeActivity.onCreate方法中执行如下方法:
private void showLoadingImage() {
LogUtil.i("show loading dialog");
ivFirstLoading.setVisibility(View.VISIBLE);
Observable.timer(CANCEL_LOADING_TIME, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber() {
@Override
public void onCompleted() {
cancelLoadingImage();
}
@Override
public void onError(Throwable e) {
cancelLoadingImage();
}
@Override
public void onNext(Long aLong) {
}
});
}
修改后:
把这个ImageView直接去掉,不再加载
修改前:
PreviewFragment加载耗时:116.924ms
private void showPreview(boolean isShow) {
LogUtil.d("showPreview isShow = " + isShow);
if (previewFragment != null) {
LogUtil.i("previewFragment");
previewFragment.setShow(isShow, 0, false);
}
setForbidScrollContainer(isShow);
setForbidScrollViewPager(isShow);
if (isShow) {
startClockAnimation();
} else {
showHomeContainer(true);
}
}
布局文件:
修改后:
PreviewFragment在launcher启动初始化的时候不再加载,而是等到进入表盘预览界面的时候才会取加载一次,然后缓存起来,这么做可能在首次进入表盘预览界面的时候由于要加载数据可能会有延迟或者闪动的效果
private void initPreviewFragment() {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
if (previewFragment == null) {
LogUtil.d("initPreviewFragment");
previewFragment = PreviewFragment.newInstance();
previewFragment.setCallback(HomeActivity.this);
fragmentTransaction.add(android.R.id.content, previewFragment, previewFragment.getClass().getSimpleName());
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
}
private void showPreview(boolean isShow) {
LogUtil.d("showPreview isShow = " + isShow);
if (isShow) {
initPreviewFragment();
}
if (previewFragment != null) {
LogUtil.i("previewFragment");
previewFragment.setShow(isShow, 0, false);
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
if (isShow) {
fragmentTransaction.show(previewFragment);
} else {
fragmentTransaction.hide(previewFragment);
}
fragmentTransaction.commitAllowingStateLoss();
}
setForbidScrollContainer(isShow);
setForbidScrollViewPager(isShow);
if (isShow) {
startClockAnimation();
} else {
showHomeContainer(true);
}
}
布局文件就把fragment去掉
修改前:
TextView加载耗时:56.017ms
,可以看到的background中decode了较多的bitmap
public void dealClockChanging() {
LogUtil.i("dealClockChanging");
setBlurImage();
if (isShow) {
rlClockChange.setVisibility(View.VISIBLE);
rlClockChange.postDelayed(runnable, 5000);
changingAnim = (AnimationDrawable) tvChanging.getBackground();
changingAnim.start();
}
}
修改后:
TextView加载耗时:5.07ms
,在初始化加载过程中不再decode bitmap
public void dealClockChanging() {
LogUtil.i("dealClockChanging");
setBlurImage();
if (isShow) {
rlClockChange.setVisibility(View.VISIBLE);
rlClockChange.postDelayed(runnable, 5000);
if (tvChanging.getBackground() == null) {
LogUtil.d("load tvChanging background");
changingAnim = (AnimationDrawable) context.getDrawable(R.drawable.anim_changing);
tvChanging.setBackground(changingAnim);
} else {
changingAnim = (AnimationDrawable) tvChanging.getBackground();
}
changingAnim.start();
}
}
修改前:HomeActivity在启动的时候加载了较多fragment,而且这些fragment在加载布局后也会取刷新数据然后又会更新界面导致在启动过程中加载布局,绘制界面,加载数据,再次绘制界面,measure的代价太大
03-16 17:27:52.838 2635-2635/com.xtc.i3launcher I/LaunchComputer: finish HomeActivity.onResume [5708] ms
03-16 17:28:09.104 2635-2635/com.xtc.i3launcher I/LaunchComputer: onWindowFocusChanged [19381] ms
如上,measure花费了4.502s时间,而且从onResume到onWindowFocusChanged需要大概10-15秒的时间
现在我们来做一个测试,把HomeActivity启动过程中需要加载的fragment先注释掉,全部不加载:
03-22 09:32:43.586: I/LaunchComputer(7512): finish HomeActivity.onResume [1582] ms
03-22 09:32:44.020: I/LaunchComputer(7512): onWindowFocusChanged [2015] ms
现在我们终于找到为什么onResume到onWindowFocusChanged需要花那么长的时间了,因为在onResume调用完了之后,系统会加载Activity中还未加载的控件(fragment),然后再进行布局的绘制(measure,layout,draw),最后添加到窗口中取然后再设置窗体可见,这时候Activity才是真正可见的,如果没有加载fragment,也没有刷新数据,自然就没有布局加载,没有界面绘制,那么从onResume到onWindowFocusChanged这个过程做的事情就很少了,因此时间花费也会很短
修改前:
在HomeActivity.onCreate方法中调用:
private void initFragment() {
FragmentManager fragmentManager = getSupportFragmentManager();
statusBarFragment = (StatusBarFragment) fragmentManager.findFragmentById(R.id.fragment_status_bar);
notificationFragment = (NotificationFragment) fragmentManager.findFragmentById(R.id.fragment_notification);
pullUpFragment = (PullUpFragment) fragmentManager.findFragmentById(R.id.fragment_pull_up);
statusBarFragment.setCallback(this);
notificationFragment.setCallback(this);
pullUpFragment.setCallback(this);
asyncInitPullUp();
homeContainer.setPullDownList(notificationFragment.getPullDownList());
}
修改后:
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
LogUtil.i("wtx hasFocus" + hasFocus);
if (hasFocus && !firstInit) {
initFragment();
LaunchComputer.trace("onWindowFocusChanged");
firstInit = true;
}
if (!hasFocus) {
DisplayUtil.setNormalScreenOffTimeout(this);
setHasSetTime(false);
} else {
setTimeOnClock();
}
startCostTimeBehavior();
}
private void initFragment() {
// 开机速度优化:让fragment变成动态加载,并且放到onWindowFocusChanged中首次初始化执行
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
statusBarFragment = StatusBarFragment.newInstance();
fragmentTransaction.add(R.id.ll_pull_down, statusBarFragment);
notificationFragment = NotificationFragment.newInstance();
fragmentTransaction.add(R.id.ll_pull_down, notificationFragment);
fragmentTransaction.commit();
/*FragmentManager fragmentManager = getSupportFragmentManager();
statusBarFragment = (StatusBarFragment) fragmentManager.findFragmentById(R.id.fragment_status_bar);
notificationFragment = (NotificationFragment) fragmentManager.findFragmentById(R.id.fragment_notification);*/
pullUpFragment = (PullUpFragment) fragmentManager.findFragmentById(R.id.fragment_pull_up);
statusBarFragment.setCallback(this);
notificationFragment.setCallback(this);
pullUpFragment.setCallback(this);
asyncInitPullUp();
homeContainer.setPullDownList(notificationFragment.getPullDownList());
}
改成动态加载fragment的方式,这样在launcher启动初始化的时候就不需要取加载布局文件中的fragment,而是等主界面看到之后才会去动态加载
private void initPromptStatus() {
if (llPromptStatus == null) {
ViewStub llPromptStatusViewStub = (ViewStub) clockLayout.findViewById(R.id.view_stub_ll_clock_prompt_status);
llPromptStatusViewStub.inflate();
llPromptStatus = (LinearLayout) clockLayout.findViewById(R.id.ll_clock_prompt_status);
llPromptStatus.setOnClickListener(this);
}
}
private void initPromptWeather() {
if (llPromptWeather == null) {
ViewStub llPromptWeatherViewStub = (ViewStub) clockLayout.findViewById(R.id.view_stub_ll_clock_prompt_weather);
llPromptWeatherViewStub.inflate();
llPromptWeather = (LinearLayout) clockLayout.findViewById(R.id.ll_clock_prompt_weather);
llPromptWeather.setOnClickListener(clickListener);
ivPromptWeatherAlarm = (ImageView) llPromptWeather.findViewById(R.id.iv_clock_prompt_weather_alarm);
}
}
修改前:
加载表盘成功后需要把View添加到布局中,会引起measure,layout,draw一些列UI绘制操作,这里主要耗时在measure操作,一共耗时:1.96s
修改后:
修改后measure操作耗时:1.702s
可以看出,仅仅加载一个ClockFragment,measure耗时2.072s,其中大部分时间耗费在OpenDexFilesFromOat操作上,第一个OpenDexFilesFromOat耗时1.125s,第二个OpenDexFilesFromOat耗时507.981ms,而我查看代码发现这个就是由于加载ClockFragment的时候取sd卡下加载dex包导致的
修改前
加载ContactFragment布局耗时40.13ms
修改后:
加载ContactFragment布局耗时34.126ms
修改前:
加载WeichatFragment的布局移动耗时:20.732ms
修改后:
替换ViewStub后WeichatFragment的布局加载耗时:11.995ms
修改前:
ForbiddenVie是一个RelativeLayout,它有加载了一套布局:
public class ForbiddenView extends RelativeLayout{
private ImageView stepIcon;
public ForbiddenView(Context context){
this(context,null);
}
public ForbiddenView(Context context, AttributeSet attrs){
this(context,attrs,0);
}
public ForbiddenView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
LayoutInflater.from(context).inflate(R.layout.i11_motion_main_forbidden,this,true);
stepIcon = (ImageView)findViewById(R.id.iv_step_icon);
}
public ImageView getHeaderTitle(){
return stepIcon;
}
}
加载MotionFragment布局耗时:70.3ms
修改后:
加载MotionFragment布局耗时:8.198ms
修改前:
加载AppFragment布局耗时:6.321ms
修改后:
加载AppFragment布局耗时:10.976ms,那么问题来了,优化过后的布局加载耗时为何比优化前的布局加载耗时要长?这不扯淡?从理论的角度取分析,优化前的布局层级是2层,优化后的布局层级是1层,因此布局加载和绘制肯定是1层布局要优于两层布局的,这个毋庸置疑,但是为何优化后的时间反而加长?事实是在加载布局的过程中,可能收到其他因素的干扰导致主线程卡顿了:
如上,再加载AppFragment布局过程中,UI线程处于sleeping状态,而此时RxIoScheduler-6处于running状态,这就说明此时的cpu资源被RxIoScheduler-6线程抢走,因此UI线程被挂起休眠,所以AppFragment布局加载到一半就在这卡了6.101ms,那么扣除这卡顿的时间,AppFragment最后大致的加载耗时为:10.976 - 6.101 = 4.875ms;注意这里的UI线程被挂起是随机的,并不是每次加载AppFragment布局的时候UI线程都会被挂起
在onCreate方法中先加载并显示ClockFragment,因为ClockFragment是最先需要马上看到的
把其他的Fragment(ContactFragment,WeichatFragment,MotionFragment,GradeFragment,AppFragment)的加载与显示放到onWindowFocusChanged当中取执行,避免在启动过程中加载大量的布局,刷新数据,绘制界面造成线程竞争,卡顿主线程,拖慢启动速度
在onWindowFocusChanged中需要用handler执行UI刷新任务,这样才不会卡住onWindowFocusChanged,导致页面显示变慢,这样能做到的效果是ClockFragment先显示,然后再取刷新其他数据
修改后的代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DisplayUtil.isCreate = true;
startMainCreateTimeMillis = SystemClock.elapsedRealtime();
LaunchComputer.trace("before setContentView for HomeActivity");
setContentView(R.layout.activity_home); // TODO: 2018/3/6 耗时
LaunchComputer.trace("setContentView for HomeActivity");
LogUtil.d("onCreate width = " + ScreenUtils.getScreenWidth(this) +
"---height = " + ScreenUtils.getScreenHeight(this));
initData();
LaunchComputer.trace("HomeActivity.initData");
initAnimation();
LaunchComputer.trace("HomeActivity.initAnimation");
initView();
LaunchComputer.trace("HomeActivity.initView");
CloudMusicReceiver.getInstance().registerReceiver(this);
EventBus.getDefault().register(this);
LaunchComputer.trace("finish HomeActivity.onCreate");
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
LogUtil.i("wtx hasFocus" + hasFocus);
if (hasFocus && !firstInit) {
firstInit = true;
LaunchComputer.trace("onWindowFocusChanged");
windowFocusedInit();
LaunchComputer.trace("windowFocused init finished");
}
if (!hasFocus) {
DisplayUtil.setNormalScreenOffTimeout(this);
setHasSetTime(false);
} else {
setTimeOnClock();
}
startCostTimeBehavior();
}
private void windowFocusedInit() {
// 开机速度优化:把一些无需马上执行的操作放到这里执行
initOther();
LaunchComputer.trace("initOther");
initFragment();
LaunchComputer.trace("initFragment");
initForPresenter();
LaunchComputer.trace("initForPresenter");
// 开机速度优化:这里用handler来post执行是为了不卡住windowFocusedInit方法
// 让onWindowFocusChanged能马上执行完成,然后再执行以下任务取刷新UI
presenter.invalidateUI(new Runnable() {
@Override
public void run() {
initClassMode();
LaunchComputer.trace("initClassMode");
initWatchLoss();
LaunchComputer.trace("initWatchLoss");
initPowerSave();
LaunchComputer.trace("initPowerSave");
initTheme();
LaunchComputer.trace("initTheme");
DisplayUtil.startWakeLock(getApplicationContext(), false);
LaunchComputer.trace("HomeActivity.startWakeLock");
SharedTool.saveOneTrafficBytes(getApplicationContext(), 0); // 开机启动流量置0,为了后面的流量统计提供使用
LaunchComputer.trace("SharedTool.saveOneTrafficBytes");
SystemBehavior.behaviorSystemInfo();
LaunchComputer.trace("behaviorSystemInfo");
ShellUtil.systemShutdownOrAppCrashBehavior(getApplicationContext());
LaunchComputer.trace("systemShutdownOrAppCrashBehavior");
SyncData.launcher(getApplicationContext());
LaunchComputer.trace("launcher");
}
});
}
SyncData.launcher(getApplicationContext())方法:
public static void launcher(final Context context) {
if (isInit) {
LogUtil.d(TAG, "已经初始化过了");
return;
}
LogUtil.d(TAG, "launcher");
isInit = true;
isLauncher = true;
isTouchWatch = false;
syncSuccess = false;
syncCompleted = false;
startSystemTaskCompleted = false;
// 设置固定时间后,自动同步数据
LogUtil.d(TAG, "手表启动,检测相关状态");
Random random = new Random();
long launcherTime = System.currentTimeMillis()
+ (1000L * 60 * (random.nextInt(20) + 10));
SystemAlarm.setAlarm(context, getInitIntent(context), launcherTime);
Intent intent = new Intent(context, InitService.class);
intent.putExtra("startSystemTask", true);
context.startService(intent);
}
把SyncData.launcher(getApplicationContext())放到HomeActivity的onWindowFocusChanged的第一次focus的时候执行,避免在Launcher启动过程中,界面还未显示就同时也去加载一些数据,可以等界面显示出来后再去加载数据也不迟
private void initOther() {
LogUtil.d("initOther");
showSimCardLock(presenter.isSimCardLock());
PopWindowManager.initPopWindow(this);
HighTemperatureReceiver.initSystemHighTemperature(this);
Intent intent = new Intent(ACTION_LAUNCHER_START);
sendBroadcast(intent);
DelayInit.execute(this);
ModemLogServeImpl.getInstance(this).checkLastModemLog(true);
TcpDumpServeImpl.getInstance(this).checkLastTcpDump();
}
修改前:
ActivityThread.java
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp");
handleReceiver((ReceiverData)msg.obj);
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
handleReceiver()方法
Application app = packageInfo.makeApplication(false, mInstrumentation);
if (localLOGV) Slog.v(
TAG, "Performing receive of " + data.intent
+ ": app=" + app
+ ", appName=" + app.getPackageName()
+ ", pkg=" + packageInfo.getPackageName()
+ ", comp=" + data.intent.getComponent().toShortString()
+ ", dir=" + packageInfo.getAppDir());
ContextImpl context = (ContextImpl)app.getBaseContext();
sCurrentBroadcastIntent.set(data.intent);
receiver.setPendingResult(data);
receiver.onReceive(context.getReceiverRestrictedContext(),
data.intent);
此广播发送后,接收者执行onReceive方法,处理广播流程的过程中耗时:136.162ms
修改后:
把initOther()方法放到HomeActivity的onWindowFocusChanged的第一次focus的时候执行,这样在Launcher启动过程中就不会取发送广播,自然也就不用处理广播了
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
LogUtil.i("wtx hasFocus" + hasFocus);
if (hasFocus && !firstInit) {
windowFocused();
LaunchComputer.trace("onWindowFocusChanged");
firstInit = true;
}
if (!hasFocus) {
DisplayUtil.setNormalScreenOffTimeout(this);
setHasSetTime(false);
} else {
setTimeOnClock();
}
startCostTimeBehavior();
}
private void windowFocused() {
initFragment();
initOther();
// 开机速度优化:把数据同步操作放到onWindowFocusChanged中执行
SyncData.launcher(getApplicationContext());
}