8.3.4 Surface和画图

下面来看最后两个和Surface相关的函数调用:一个是lockCanvas;另外一个是unlockCanvasAndPost。

1.lockCanvas分析

要对lockCanvas进行分析,须先来看Java层的函数,代码如下所示:


[—>Surface.java:lockCanvas()]

public Canvas lockCanvas(Rect dirty)

throws OutOfResourcesException,IllegalArgumentException

{

return lockCanvasNative(dirty);//调用native的lockCanvasNative函数。

}

[—>android_view_Surface.cpp:Surface_lockCanvas()]

static jobject Surface_lockCanvas(JNIEnv*env,jobject clazz,jobject dirtyRect)

{

//从Java中的Surface对象中,取出费尽千辛万苦得到的Native的Surface对象。

const sp<Surface>&surface(getSurface(env,clazz));

……

//dirtyRect表示需要重绘的矩形块,下面根据这个dirtyRect设置dirtyRegion。

Region dirtyRegion;

if(dirtyRect){

Rect dirty;

dirty.left=env->GetIntField(dirtyRect,ro.l);

dirty.top=env->GetIntField(dirtyRect,ro.t);

dirty.right=env->GetIntField(dirtyRect,ro.r);

dirty.bottom=env->GetIntField(dirtyRect,ro.b);

if(!dirty.isEmpty()){

dirtyRegion.set(dirty);

}

}else{

dirtyRegion.set(Rect(0x3FFF,0x3FFF));

}

//调用Native Surface对象的lock函数,

//传入了一个参数Surface:SurfaceInfo info和一块表示脏区域的dirtyRegion。

Surface:SurfaceInfo info;

status_t err=surface->lock(&info,&dirtyRegion);

……

//Java的Surface对象构造的时候会创建一个CompatibleCanvas。

//这里就取出这个CompatibleCanvas对象。

jobject canvas=env->GetObjectField(clazz,so.canvas);

env->SetIntField(canvas,co.surfaceFormat,info.format);

//从Canvas对象中取出SkCanvas对象。

SkCanvasnativeCanvas=(SkCanvas)env->GetIntField(

canvas,no.native_canvas);

SkBitmap bitmap;

ssize_t bpr=info.s*bytesPerPixel(info.format);

bitmap.setConfig(convertPixelFormat(info.format),info.w,info.h,bpr);

……

if(info.w>0&&info.h>0){

//info.bits指向一块存储区域。

bitmap.setPixels(info.bits);

}else{

bitmap.setPixels(NULL);

}

//给这个SkCanvas设置一个Bitmap,还记得前面说的画图需要的四大金刚吗?

//这里将Bitmap设置到这个Canvas中,这样进UI绘画时就有画布了。

nativeCanvas->setBitmapDevice(bitmap);

……

return canvas;

}


lockCanvas还算比较简单:

先获得一块存储区域,然后将它和Canvas绑定到一起,这样,UI绘画的结果就记录在这块存储区域里了。

注意 本书不打算讨论Android系统上Skia和OpenGL方面的知识,有兴趣的读者可自行研究。

接下来看unlockCanvasAndPost函数,它也是一个native函数。

2.unlockCanvasAndPost分析

来看unlockCanvasAndPost的代码,如下所示:


[—>android_view_Surface.cpp]

static void Surface_unlockCanvasAndPost(JNIEnv*env,jobject clazz,

jobject argCanvas)

{

jobject canvas=env->GetObjectField(clazz,so.canvas);

//取出Native的Surface对象。

const sp<Surface>&surface(getSurface(env,clazz));

//下面这些内容就讨论了,读者若有兴趣,可结合Skia库自行研究。

SkCanvasnativeCanvas=(SkCanvas)env->GetIntField(canvas,

no.native_canvas);

int saveCount=env->GetIntField(clazz,so.saveCount);

nativeCanvas->restoreToCount(saveCount);

nativeCanvas->setBitmapDevice(SkBitmap());

env->SetIntField(clazz,so.saveCount,0);

//调用Surface对象的unlockAndPost函数。

status_t err=surface->unlockAndPost();

……

}


unlockCanvasAndPost也很简单,这里就不再多说了。