背景
最近产品以及测试大佬反应快搜桌面进入搜索页面跳转较为缓慢,影响体验,为了优化这个问题,特地学习Android 性能优化工具 TraceView的 简单使用,这才有了本文。
正文
如下图打开android device monitor ,打开有点慢,请耐心等待:

可能有些同学会打不开,出现如下的错误:

重装一遍jdk,配好环境变量一般就没有问题了。android device monitor打开之后如图:

可以看到TraceView 集成了很多小工具,图上标红的1是个截取设备当前屏幕的工具,作为和测试后台交(si)流(bi)的神器,能做到有图有真相;图上标红的2由于展示当前页面视图层级结构,如下图:

可以看到右边上半部分可以很清晰看到当前页面视图的结构,下半部分显示的是选择的视图的一些信息,如位置信息等,这个工具的应用场景还是很广泛的,比如产品大佬叫你改一个view的文本,有了这个工具你可以很快定位到要改的是哪个,上图左边还有好多小工具,这些不是本次的重点,有机会再说,不得不说一句,Google 大法好!!
言归正传,选中你要分析的进程,如图:

红色1表示的位置由原来的灰色不可用的状态变为可用状态,敲黑板啦,重点来了。这个按钮叫 start method profiling(开始方法分析),点击之后如图:

点击OK,会对接下来的操作进行跟踪分析,这里我点击了跳转搜索页面的操作,然后在点击刚刚那个按钮,注意到按钮变成了 stop method profiling(停止方法分析),稍等一下就有分析结果视图如下:

先简单介绍下这个视图,红色1主要表示当前选中方法调用的线程信息,红色2表示的的是时间线,当你点击红色3区域的时候,时间线视图会有相应的反馈,出现一个U型闪动,U型宽度就是方法的执行时间,可以将借助鼠标测量耗时,如图先放到起点:

注意红线部分表示当前时间,再把鼠标放到U型的结束位置,如下图:

两者相减就能知道方法耗时,其实这个功能有点鸡肋,一般不用,接下来我会介绍红色3区域的功能,更加方便:

可以看到这是个表格,代表的含义如下:
| 列名 | 含义 |
|---|---|
| Name | 该线程运行过程中所调用的函数名 |
| Incl Cpu Time | 某函数占用的CPU时间,包含内部调用其它函数的CPU时间 |
| Excl Cpu Time | 某函数占用的CPU时间,但不含内部调用其它函数所占用的CPU时间 |
| Incl Real Time | 某函数运行的真实时间(以毫秒为单位),不含调用其它函数所占用的真实时间 |
| Excl Real Time | 某函数运行的真实时间(以毫秒为单位),不含调用其它函数所占用的真实时间 |
| Call+Recur Calls/Total | 某函数被调用次数以及递归调用占总调用次数的百分比 |
| Cpu Time/Call | 某函数调用CPU时间与调用次数的比。相当于该函数平均执行时间 |
| Real Time/Call | 同CPU Time/Call类似,只不过统计单位换成了真实时间 |
随便点击一个函数,Parent表示调用该方法的方法,Children表示该方法调用的方法 ,如下:

可以看到LauncherSearchActvity的oncreate方法耗时1006.735这个很不正常,再找到Children里面耗时最多的setContenView,一步步下去,最后定位到如下的位置:



for (int i = 0; i < 6; i++) {
for (int j = 0; j < 6; j++) {
GonTextView mButton = new GonTextView(getContext());
mButton.setFocusable(true);
mButton.setGravity(Gravity.CENTER);
if (j == 5) {
mButton.setOnKeyListener(this);
mButton.setTag(RIGHT_ROW_TAG);
} else if (j == 0) {
mButton.setId(DEFAULT_FOCUS_VIEW_ID);
}
mButton.getPaint().setFakeBoldText(true);
mButton.setText(text_str[i][j]);
ImageUtils.setBackground(mButton, R.drawable.sel_search_keyboard_item_solid);
mButton.setTextColor(ResUtil.getColorList(isKeyboardNum(text_str[i][j]) ? R.color.sel_color_search_keyboard_item_123 : R.color.sel_color_search_keyboard_item_abc));
keyboardAcherView.addView(mButton);
//adapter
mButton.setGonTextSize(38);
mButton.setGonSize(70, 70);
mButton.setGonMargin(j * (24 + 70), i * (24 + 70), 0, 0);
// gain defualt focus item
if (i == 0 && j == 0) {
mButton.requestFocus();
}
mButton.setOnClickListener(v -> editText.append(((TextView) v).getText().toString()));
}
}可以看到36次循环,所以出现了上上张图的Call+Recur Calls/Total中的值是36/36,这边可以简单优化下,将键码GonTextView 放到一个集合里面,这步的操作放在子线程,然后在主线程遍历,addView()就好了,代码如下:
Observable.create((ObservableOnSubscribe<ArrayList<ViewWrapper>>) e -> {
ArrayList<ViewWrapper> gonTextViews = initKeys();
e.onNext(gonTextViews);
e.onComplete();
}).subscribeOn(RxCompat.getSchedulerOnDb())
.observeOn(RxCompat.getSchedulerOnMain()).subscribe(new RxCompatObserver<ArrayList<ViewWrapper>>() {
@Override
public void onSubscribeCompat(Disposable d) {
}
@Override
public void onNextCompat(ArrayList<ViewWrapper> gonTextViews) {
GonRelativeLayout keyboardAcherView = (GonRelativeLayout) findViewById(R.id.ll_keys);
keyboardAcherView.removeAllViews();
for (ViewWrapper viewWrapper : gonTextViews) {
keyboardAcherView.addView(viewWrapper.gonTextView);
// keyboardAcherView.reqLa
//adapter
viewWrapper.gonTextView.setGonTextSize(38);
viewWrapper.gonTextView.setGonSize(70, 70);
viewWrapper.gonTextView.setGonMargin(viewWrapper.x * (24 + 70), viewWrapper.y * (24 + 70), 0, 0);
if (viewWrapper.x == 0 && viewWrapper.y == 0) {
viewWrapper.gonTextView.requestFocus();
}
}
setVisibility(VISIBLE);
if (SpUtil.getBoolean(SpUtil.SpKey.IS_INPUT_METHOD, false)) {
postDelayed(() -> btnInputMethod.performClick(), 50);
}
}
});
private ArrayList<ViewWrapper> initKeys() {
ArrayList<ViewWrapper> gonTextViews = new ArrayList<>(36);
String[][] text_str = new String[][]{
{"A", "B", "C", "D", "E", "F"},
{"G", "H", "I", "J", "K", "L"},
{"M", "N", "O", "P", "Q", "R"},
{"S", "T", "U", "V", "W", "X"},
{"Y", "Z", "1", "2", "3", "4"},
{"5", "6", "7", "8", "9", "0"}
};
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 6; j++) {
GonTextView mButton = new GonTextView(getContext());
mButton.setFocusable(true);
mButton.setGravity(Gravity.CENTER);
if (j == 5) {
mButton.setOnKeyListener(this);
mButton.setTag(RIGHT_ROW_TAG);
} else if (j == 0) {
mButton.setId(DEFAULT_FOCUS_VIEW_ID);
}
mButton.getPaint().setFakeBoldText(true);
mButton.setText(text_str[i][j]);
ImageUtils.setBackground(mButton, R.drawable.sel_search_keyboard_item_solid);
mButton.setTextColor(ResUtil.getColorList(isKeyboardNum(text_str[i][j]) ? R.color.sel_color_search_keyboard_item_123 : R.color.sel_color_search_keyboard_item_abc));
gonTextViews.add(new ViewWrapper(i,j,mButton));
mButton.setOnClickListener(v -> editText.append(((TextView) v).getText().toString()));
}
}
return gonTextViews;
}结果如图:

从原来的1000多毫秒到不到300毫秒,提升还是很大的!
码字不易,期待各位的赞赏!!!
