registerAnimatingRenderNode(
attachInfo.mPendingAnimatingRenderNodes.get(i));
}
attachInfo.mPendingAnimatingRenderNodes.clear();
//Wedon'tneedthisanymoreassubsequentcallsto
//ViewRootImpl#attachRenderNodeAnimatorwillgodirectlytous.
attachInfo.mPendingAnimatingRenderNodes=null;
}
intsyncResult=nSyncAndDrawFrame(mNativeProxy,frameTimeNanos,
recordDuration,view.getResources().getDisplayMetrics().density);
if((syncResult&SYNC_INVALIDATE_REQUIRED)!
=0){
attachInfo.mViewRootImpl.invalidate();
}
}
......
}
这个函数定义在文件frameworks/base/core/Java/android/view/ThreadedRenderer.java中。
ThreadedRenderer类的成员函数draw主要是完成以下四件事情:
1.调用成员函数updateRootDisplayList构建参数view描述的视图的DisplayList,该视图即为图1所示的DecorView。
2.调用成员函数registerAnimatingRenderNode将保存在参数attachInfo指向的一个AttachInfo对象的成员变量mPendingAnimatingRenderNodes描述的一个列表中的RenderNode注册到Native层中去。
这些RenderNode描述的是当前窗口设置的动画。
3.调用成员函数nSyncAndDrawFrame通知RenderThread绘制下一帧。
4.如果成员函数nSyncAndDrawFrame的返回值syncResult的SYNC_INVALIDATE_REQUIRED位不等于0,就表明RenderThread可能需要与MainThread进行信息同步,这时候就时候向MainThread发送一个INVALIDATE消息,以便MainThread可以进行信息同步。
这种情况一般发生在当前绘制的一帧包含有同步动画时。
例如,同步动画显示到一半,需要中止,这个中止的操作就是由MainThread发出的,然后由RenderThread检测到这个中止操作。
这里我们只关注第一件事情,其余三件事情在接下来的两篇文章中再详细分析。
ThreadedRenderer类的成员函数updateRootDisplayList的实现如下所示:
[java]viewplaincopy
publicclassThreadedRendererextendsHardwareRenderer{
......
privatevoidupdateRootDisplayList(Viewview,HardwareDrawCallbackscallbacks){
......
updateViewTreeDisplayList(view);
if(mRootNodeNeedsUpdate||!
mRootNode.isValid()){
HardwareCanvascanvas=mRootNode.start(mSurfaceWidth,mSurfaceHeight);
try{
finalintsaveCount=canvas.save();
.......
canvas.insertReorderBarrier();
canvas.drawRenderNode(view.getDisplayList());
canvas.insertInorderBarrier();
......
canvas.restoreToCount(saveCount);
mRootNodeNeedsUpdate=false;
}finally{
mRootNode.end(canvas);
}
}
......
}
......
}
这个函数定义在文件frameworks/base/core/java/android/view/ThreadedRenderer.java中。
ThreadedRenderer类的成员函数updateRootDisplayList通过调用另一个成员函数updateViewTreeDisplayList来构建参数view描述的视图的DisplayList,即图1中的DecorView的DisplayList。
构建好的这个DisplayList可以通过调用参数view描述的视图的成员函数getDisplayList获得的一个RenderNode来描述。
ThreadedRenderer类的成员变量mRootNodeNeedsUpdate是一个布尔变量,当它的值等于true的时候,就表示要更新另外一个成员变量mRootNode描述的一个RenderNode的DisplayList。
另外,如果ThreadedRenderer类的成员变量mRootNode描述的RenderNode还未构建过DisplayList,那么这时候调用它的成员函数isValid的返回值为true,这种情况也表示要更新它的DisplayList。
从前面一文可以知道,ThreadedRenderer类的成员变量mRootNode描述的RenderNode即为即为当前窗口的RootNode,更新它的DisplayList实际上就是要将参数view描述的视图的DisplayList记录到它里面去,具体方法如下所示:
1.调用ThreadedRenderer类的成员变量mRootNode描述的RenderNode的成员函数start获得一个HardwareCanvas。
2.调用上面获得的HardwareCanvas的成员函数drawRenderNode将参数view描述的视图的DisplayList绘制在它里面。
在绘制参数view描述的视图的DisplayList的前后,会调用HardwareCanvas的成员函数insertReorderBarrier和insertInorderBarrier分别设置一个ReorderBarrier和一个InorderBarrier。
后面我们在分析DisplayList绘制在HardwareCanvas的过程时就会看到,插入这些Barrier是为了将一个View的所有的DrawOp及其子View对应的DrawOp记录在一个Chunk中。
其中,ReorderBarrier表明在真正渲染这些Chunck记录的DrawOp时,需要考虑按照Z轴坐标值重新排列子View的渲染顺序。
3.调用ThreadedRenderer类的成员变量mRootNode描述的RenderNode的成员函数end取出上述已经绘制好的HardwareCanvas的数据,并且作为上述RenderNode的新的DisplayList。
接下来,我们首先分析ThreadedRenderer类的成员变量mRootNode描述的RenderNode的DisplayList的更新过程,即RootNode类的成员函数start、HardwareCanvas类的成员函数drawRenderNode和RootNode类的成员函数end的实现,然后再回过头来分析参数view描述的视图的DisplayList的构建过程,即ThreadedRenderer类的成员函数updateViewTreeDisplayList的实现。
RootNode类的成员函数start的实现如下所示:
[java]viewplaincopy
publicclassRenderNode{
......
publicHardwareCanvasstart(intwidth,intheight){
HardwareCanvascanvas=GLES20RecordingCanvas.obtain(this);
canvas.setViewport(width,height);
......
returncanvas;
}
......
}
这个函数定义在文件frameworks/base/core/java/android/view/RenderNode.java中。
RootNode类的成员函数start的核心是调用GLES20RecordingCanvas类的静态成员函数obtain一个类型为GLES20RecordingCanvas的HardwareCanvas,然后在设置了该HardwareCanvas的ViewPort之后,返回给调用者。
GLES20RecordingCanvas类的静态成员函数obtain的实现如下所示:
[java]viewplaincopy
[java]viewplaincopy
classGLES20RecordingCanvasextendsGLES20Canvas{
......
privatestaticfinalintPOOL_LIMIT=25;
privatestaticfinalSynchronizedPoolsPool=
newSynchronizedPool(POOL_LIMIT);
RenderNodemNode;
privateGLES20RecordingCanvas(){
super();
}
staticGLES20RecordingCanvasobtain(@NonNullRenderNodenode){
......
GLES20RecordingCanvascanvas=sPool.acquire();
if(canvas==null){
canvas=newGLES20RecordingCanvas();
}
canvas.mNode=node;
returncanvas;
}
......
}
这个函数定义在文件frameworks/base/core/java/android/view/GLES20RecordingCanvas.java中。
GLES20RecordingCanvas类的静态成员函数obtain首先是从一个GLES20RecordingCanvas对象池中请求一个GLES20RecordingCanvas对象。
如果获取失败,再直接创建一个GLES20RecordingCanvas对象。
在将获取到的GLES20RecordingCanvas对象返回给调用者之前,还会将参数node描述的RenderNode保存在其成员变量mNode中。
接下来我们继续关注GLES20RecordingCanvas对象的创建过程,即GLES20RecordingCanvas类的构造函数的实现。
GLES20RecordingCanvas类的构造函数只是简单调用了父类GLES20Canvas的构造函数,它的实现如下所示:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
classGLES20CanvasextendsHardwareCanvas{
......
protectedlongmRenderer;
......
protectedGLES20Canvas(){
......
mRenderer=nCreateDisplayListRenderer();
......
}
......
}
这个函数定义在文件frameworks/base/core/java/android/view/GLES20Canvas.java中。
GLES20Canvas类的构造函数最主要做的事情就是调用另外一个成员函数nCreateDisplayListRenderer在Native层创建了一个DisplayListRenderer,并且将它的地址保存在成员变量mRenderer中。
GLES20Canvas类的成员函数nCreateDisplayListRenderer是一个JNI函数,由Native层的函数android_view_GLES20Canvas_createDisplayListRenderer实现,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
staticjlongandroid_view_GLES20Canvas_createDisplayListRenderer(JNIEnv*env,jobjectclazz){
returnreinterpret_cast(newDisplayListR