大部分 Android 应用程式,应该都是用 Java Code 完成所有的工作,包括绘图。但,有些情况下,你会希望绘图有更快的反应;例如 game ,这时 native code 可能是一个选择。
在 Android 上,有一个 graphic engine ,称为 Skia 。 Skia 的功能约等于 Cairo ,功能上相似,但 Skia 的支援没 Cairo 广。其实, Android 的 Java Code 都是透过 Skia 进行绘图,而 Skia 主要的 class type 是 SkCanvas ,所的有绘图功能都建构在这个 class 上。因此,如果我们能在 native code 取得 Android 所建立的 SkCanvas ,能直接使用 Skia 对画面做输出。
在 Android 的 UI 设计裡,每一个 UI component 都是一个 view ;例如: button 、 label 等等,全是 view 。当 Android 要画一个 view 时,会呼叫 view 的 onDraw() 画出 component 的外观。而 Android 会将一个 android.graphics.Canvas type 的物件,当成参数给 onDraw() 。 onDraw() 就在这个 canvas 上输出 component 的外观,例如画一个 button 。这个 canvas 其实就对映到一个 SkCanvas ,我们只要在这个 canvas 上作画,就等于画到画面上的一个区域。
Native code
Android 是透过 JNI 呼叫 native code ,于是我们在 Java side 定义了一个 View ,使该 View 透过 JNI 把 canvas 传送给我们的 native code ,以便在 native code 裡绘图。
#!cpp
package com.example;
import android.view.View;
import android.graphics.Canvas;
class myview extends View {
public void onDraw(Canvas canvas) {
nativedraw(canvas);
}
native void nativedraw(Canvas canvas);
static {
System.loadLibrary("mynative");
}
}
在个这 class 裡,我们将 canvas 透过 JNI 传给 native code ,接下来我们定义 JNI 的 native function 。
#!cpp
#include <SkCanvas.h>
extern "C" {
#include <jni.h>
void
Java_com_example_myview_nativedraw(JNIEnv *env, jobject thiz, jobject obj) {
jclass cls;
jfieldID fid;
SkCanvas *canvas;
cls = env->GetObjectClass(obj);
fid = env->GetFieldID(cls, "mNativeCanvas", "I");
canvas = (SkCanvas *)env->GetIntField(obj, fid);
/* ..... draw on canvas .... */
}
}