内存
思考下,内存占用率很高的时候,UI会卡吗?
先考虑Windows,在内存不足时会采用虚拟内存策略,硬盘到内存的IO是比较占CPU的。
手机一般不开启虚拟内存。
1.但是手机内存大的时候依然会引发卡顿,因为你的内存很大,当你比如新打开一个活动或者做了需要很多内存的操作,内存就会到达阈值,引发GC,这样也会卡!(你需要关注gc情况带来的卡顿)
2.还有内存抖动,瞬间产生大量对象在年轻代中,然后gc。qwAV0
内存不是UI卡顿的瓶颈,CPU才是。但是维持内存在一个低水平上,还是很有必要的。
CPU
假如在onCreate里开一个无限循环,肯定就黑屏然后ANR,当然现在不管大厂还是外包公司的开发者,都不会写出ANR的代码,但是绝对有运算速度的高下之分。这也是为啥大厂喜欢招算法好的人,算法好的人对大大小小的需求都能建模,对性能更敏感, 明白时间复杂度,明白性能瓶颈。 (而且AC了那么多题,代码肯定是没有太多bug的)打个最简单的比方,什么时候用ArrayList,什么时候用LinkedList?什么时候用HashMap,什么时候用ArrayMap(SparseArray更是解决了装箱问题)?所以CPU也是值得关注的。
工具
1.GPU Rendering
蓝色:创建Canvas,把绘制命令保存到DisplayList中,交给RenderNode管理,最后递归由ThreadedRenderer管理。
红色:OpenGL绘制DisplayList,然后GPU来渲染
黄色:CPU告诉GPU,“你已经完成渲染了”,然后阻塞,直到GPU回应,“已完成渲染“
2.SysTrace,当你发现GPU Rendering某个时候柱状图飚的特别高, 可以用这个工具定位到具体的方法
3.过度绘制
4.采用Chographer检测FPS,Looper dispatchMessage,前后有log,而绘制的时候是必须发送一条Handler信息的。所以可以重写一个printer既可以了。
merge
源码483行
if (TAG_MERGE.equals(name)) {
if (root == null || !attachToRoot) {
throw new InflateException("<merge /> can be used only with a valid "
+ "ViewGroup root and attachToRoot=true");
}
rInflate(parser, root, inflaterContext, attrs, false);
} else {
// Temp is the root view that was found in the xml
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
if (root != null) {
if (DEBUG) {
System.out.println("Creating params from root: " +
root);
}
// Create layout params that match root, if supplied
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
// Set the layout params for temp if we are not
// attaching. (If we are, we use addView, below)
temp.setLayoutParams(params);
}
}
if (DEBUG) {
System.out.println("-----> start inflating children");
}
// Inflate all children under temp against its context.
rInflateChildren(parser, temp, attrs, true);
if (DEBUG) {
System.out.println("-----> done inflating children");
}
// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {
root.addView(temp, params);
}
// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
result = temp;
}
}
merge的话会忽略这层标签,把所有的子View加到父布局中;正常的view是add了。
ViewStub
一开始就一个View什么都不干,然后等加载的时候remove自身,add绑定的view即可。
过度绘制的优化
正常的情况不讲了,自定义View可以用canvas.clipRect
嵌套优化
由于RelativeLayout、LinearLayout等复杂ViewGroup,会measure2次,所以如果多层嵌套,其测绘次数会呈几何级上升。可以用宽度 适配+ConstrantLayout解决,其他方法面面都需要经验。比如文字、图片共存,可以写一个自定义View;看一看最简单的底部分割线,用View的例子比比皆是,其实完全可以自定义View或者inset xml + linear divider。
过度绘制+嵌套优化勉强算是瓶颈,处理了这两点后,会流畅的多。此外复杂的动画逻辑也是常见的瓶颈。
基本上过度绘制+ 嵌套优化解决了,界面已经很流畅了,还想再流畅点?先把你做到这两点好吧!看起来简单,可是你真的做到了吗?
最后别忽视内存和CPU