一、每个View的DisplayList对象之间有什么关系呢?
我们先来解决上文的遗留问题,每个View的DisplayList对象之间有什么关系呢?还记得View的draw2函数吗:
boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
......
useDisplayListProperties &= hasDisplayList;
if (useDisplayListProperties) {
displayList = getDisplayList();
if (!displayList.isValid()) {
// Uncommon, but possible. If a view is removed from the hierarchy during the call
// to getDisplayList(), the display list will be marked invalid and we should not
// try to use it again.
displayList = null;
hasDisplayList = false;
useDisplayListProperties = false;
}
}
......
if (!layerRendered) {
if (!hasDisplayList) {
// Fast path for layouts with no backgrounds
if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
dispatchDraw(canvas);
} else {
draw(canvas);
}
} else {
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
((HardwareCanvas) canvas).drawDisplayList(displayList, null, flags);
}
}
......
}
draw2函数中的((HardwareCanvas) canvas).drawDisplayList(displayList, null, flags)我们还没分析。首先这里的canvas是父View传递给我们的,并且该canvas是一个GLES20RecordingCanvas对象。所以我们来看看GLES20RecordingCanvas的drawDisplayList函数:
@Override
public int drawDisplayList(DisplayList displayList, Rect dirty, int flags) {
int status = super.drawDisplayList(displayList, dirty, flags);
mDisplayList.getChildDisplayLists().add(displayList);
return status;
}
我们看到mDisplayList.getChildDisplayLists().add(displayList)这句话,因为canvas是父View的canvas,所以canvas对应的mDisplayList对象就是父View的DisplayList对象,看一下getChildDisplayList()函数:
ArrayList<DisplayList> getChildDisplayLists() {
if (mChildDisplayLists == null) mChildDisplayLists = new ArrayList<DisplayList>();
return mChildDisplayLists;
}
所以每个父View的DisplayList都有一个ArrayList用来保存子View的DisplayList,这样每个View对应的DisplayList对象也组成了一棵树?但是千万别高兴的太早,我们之前讲过每个DisplayList的java对象都有一个对应的本地DIsplayList对象,本地DisplayList对象才是真正保存绘制操作的地方。照理说通过java层的DisplayList组成的树,本地DisplayList对象也可以联系在一起,但这会反复在java层和本地层之间进行切换,效率可能会比较低,所以Android也将本地DisplayList对象直接联系在一起了,我们来看是怎么联系的。我们回到GLES20RecordingCanvas的drawDisplayList函数,它其实先调用了super.drawDisplayList(displayList, dirty, flags)方法,GLES20RecordingCanvas的父类是GLES20Canvas,看一下GLES20Canvas的drawDisplayList方法:
@Override
public int drawDisplayList(DisplayList displayList, Rect dirty, int flags) {
return nDrawDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList(),
dirty, flags);
}
再看nDrawDisplayList方法,在core\jni\android_view_GLES20Canvas中:
static jint android_view_GLES20Canvas_drawDisplayList(JNIEnv* env,
jobject clazz, jlong rendererHandle, jlong displayListHandle,
jobject dirty, jint flags) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererHandle);
Disp