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也很简单,这里就不再多说了。