Android UI流畅度优化

内存

思考下,内存占用率很高的时候,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

猜你喜欢

转载自blog.csdn.net/qq_36523667/article/details/81139440