为什么要研究这个东西?
以往Android开发中,大部分的界面都是由xml文件写的布局文件渲染而成,控件的摆放位置,以及控件数量都是固定不变的,如果说会变化的,那么大概就是AdapterView这样的列表组件了。但是,里面的列表项中的内容,其实还是固定不变的。
但是,如果遇到一切都是变化,整个页面都是由前端页面组织好,然后返回一串关于控件的坐标位置一堆信息,要求Android移动端,能够根据给定的坐标信息动态的显示控件位置的需求,怎么办?
有人说简单,不用布局文件了,可以改用代码来写啊。不错,确实代码执行起来效率会比加载布局文件来的快。但是问题来了,如果控件是动态添加的,而且控件数量非常的多怎么办?
Android组件的生命周期
- onMeasure
- onLayout
- onDraw
这三个不用多做介绍了,相信能有需求看到这篇文章的开发者对这三个回调函数都熟烂了。
那么,我想说的事,在我开发的过程中,如果一个组件添加上百个,上千个的子控件会怎么样?
直接ANR,然后退出程序。为什么?
大家在打印日志的时候应该可以看到,onMeasure和onLayout函数其实在界面渲染的时候,被多次的调用了。至于为什么,其实很简单看了ViewGroup的源码之后都会知道,每次addView都会调用requestLayout这个方法。
这个方法会做什么事情?
这个函数做的事情,简单的来理解就是会重新的让系统重新绘制整个页面上的控件,也就是说,会重新的走一遍组件的生命周期。执行onMeasure,onLayout,onDraw。这也就是为什么,简单的用代码来动态添加控件数量的一个问题,数量少还没什么,数量一多,必然会ANR。因为父组件需要在onMeasure和onLayout中分别计算子控件的大小,以及子控件如何摆放。如果要添加1000个控件,那么········
1+2+2+4+5+6······+1000次执行生命周期的回调函数,想想看看,如果子控件还有包含子控件怎么办?
解决方案
其实可以从父类布局添加子控件这个过程中动点手脚,其实很简单,如果一个控件在父类的组件执行onMeasure和onLayout之后,能够让父类组件知道这个子控件不需要再进行计算调整不就行了?
仅仅只需要在子控件中添加一个标识,然后在父组件回调onLayout之后,让这个子控件的标识变为不需要计算,那么就可以进行跳过。就无需每次都进行一次重复的计算了。
那么如果遇到其中的一个子控件需要重新布局绘制怎么办?简单,就两步:
设置标识,让父组件知道这个子控件可以进行重新计算和重新布局,以及重新绘制。
子控件执行invalidate()即可。
如果按照上面的操作来走,相信能够提升非常多的页面渲染效率。如果是在大量控件绘制的情况下。