View Hierarchy的绘制过程的第一步是DisplayList录制绘制操作。
一、绘制操作是什么?
DisplayList是将绘制操作保存下来,那我们先看看绘制操作是什么。比如说drawBitmap就是一个绘制操作,Android将它封装成一个DrawBitmapOp
class DrawBitmapOp : public DrawBoundedOp {
public:
........
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawBitmap(mBitmap, mLocalBounds.left, mLocalBounds.top,
getPaint(renderer));
}
........
};
drawPath,drawColor,drawRect,drawArc等等都会有这样的Operation对象对应。详见libs\hwui\DisplayListOp.h。
二、DisplayList如何保存绘制操作?
说DisplayList保存绘制操作其实也不是十分准确。在GLES20DisplayList(DisplayList的实现类)中其实有个内部类DisplayListFinalizer,该类中有个mNativeDisplayList的成员变量,它指向一个C++对象。因为Java中没有指针变量,所以用长整形来保存C++对象的地址。这个本地对象才是真正保存绘制操作的对象。
private static class DisplayListFinalizer {
final long mNativeDisplayList;
public DisplayListFinalizer(long nativeDisplayList) {
mNativeDisplayList = nativeDisplayList;
}
@Override
protected void finalize() throws Throwable {
try {
nDestroyDisplayList(mNativeDisplayList);
} finally {
super.finalize();
}
}
}
本地DisplayList对象的头文件在\libs\hwui\DisplayList.h,该对象有个mDisplayListData的成员变量,而DisplayListData中有个displayListOps的成员变量,该变量是个Vector容器类型,保存一个个DisplayListOp对象。
class DisplayListData : public LightRefBase<DisplayListData> {
public:
LinearAllocator allocator;
Vector<DisplayListOp*> displayListOps;
......
};
三、从drawBitmap函数到DrawBitmapOp对象的过程。
Android如何将调用一次drawBitmap的操作转变成DrawBitmapOp对象保存起来?我们从java层canvas.drawBitmap(...)函数开始。canvas的真正类型决定了drawBitmap的不同行为。这里的canvas可能有三种类型Canvas,GLES20Canvas,GLES20RecordingCanvas。如果是Canvas,则我们没有使用硬件加速来加速,具体就不分析了。其实GLES20Canvas和GLES20RecordingCanvas的drawBitmap函数是一样的,因为GLES20RecordingCanvas是继承的GLES20Canvas,而且GLES20RecordingCanvas并没有重写drawBitmap方法:
@Override
public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
throwIfCannotDraw(bitmap);
// Shaders are ignored when drawing bitmaps
int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
try {
final long nativePaint = paint == null ? 0 : paint.mNativePaint;
nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
}
我们看到drawBitmap调用了一个本地方法nDrawBitmap方法。该方法的第一个参数传入的是GLES20Canvas的一个成员变量mRenderer,指向一个本地对象(上文已经提过java中如何指向本地对象)。GLES20Canvas和GLES20RecordingCanvas主要的区别就是这个参数。
protected GLES20Canvas(boolean record, boolean translucent) {
mOpaque = !translucent;
if (record) {
mRenderer = nCreateDisplayListRenderer();
} else {
mRenderer = nCreateRenderer();
}
setupFinalizer();
}
在创建GLES20Canvas对象时,record是false,而在创建GLES20RecordingCanvas对象时,record为true。nCreateDisplayListRenderer()和nCreateRenderer()函数的实现都在core\jni\android_view_GLES20Canvas.cpp中:
static jlong android_view_GLES20Canvas_createRenderer(JNIEnv* env, jobject clazz) {
RENDERER_LOGD("Create OpenGLRenderer");
OpenGLRenderer* renderer = new OpenGLRenderer();
renderer->initProperties();
return reinterpret_cast<jlong>(renderer);
}
static jlong android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env,
jobject clazz) {
OpenGLRenderer* renderer = new DisplayListRenderer();
return reinterpret_cast<jlong>(renderer);
}
所以GLES20Canvas中mRenderer指向的是一个OpenGLRenderer本地对象,GLES20RecordingCanvas中mRenderer指向的是一个DisplayListRenderer本地对象。我们在回到drawBitmap函数中,它会调用本地方法nDrawBitmap,该函数的实现也在core\jni\android_view_GLES20Canvas.cpp中: