class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource
显示视图,提供图形绘制函数、触屏事件、按键事件函数等,在UI主线程内更新画面,用于被动更新画面
class SurfaceView extends View
适合游戏的开发,类似使用双缓机制,在新的线程中更新画面,主动更新画面
SDL2 使用 SurfaceView,在 SurfaceView 创建完成后,起一个线程来初始化 SDL 并开始主循环
class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
专用于游戏开发的视图,OpenGL专用,主动更新画面
cocos2dx 使用 GLSurfaceView,在 GLSurfaceView 的 onDrawFrame 函数中驱动主循环
class NativeActivity extends Activity implements SurfaceHolder.Callback2, InputQueue.Callback, OnGlobalLayoutListener
完全用 NDK 开发应用,使用 EGL 在 activity 上创建 Opengl 的画布,起一个线程开始主循环
使用示例:NVIDIAGameWorks/OpenGLSamples
JNI 调用示例:
package com.foobar.helloapp; import android.view.Surface; import android.app.Activity; public class JNIWrapper { static { System.loadLibrary("main"); } public static native void load_activity(Activity activity); public static native void on_surface_created(Surface surface); public static native void on_surface_changed(int width, int height); public static native void on_draw_frame(long current); public static native void on_touch_event(int touch_device_id_in, int pointer_finger_id_in, int action, float x, float y, float p); public static native void on_pause(); public static native void on_resume(); }
将 java 代码编译成 class 文件,然后使用 javah 导出 c 的头文件
# -classpath 指定class路径,-bootclasspath 指定 android sdk,-d 指定输出目录 javah -classpath HelloApp/app/build/intermediates/classes/debug -bootclasspath android/sdk/platforms/android-19/android.jar -d jni com.foobar.helloapp.JNIWrapper
使用 c 调用 java 方法:
// android display metrics struct DisplayMetrics { int widthPixels; int heightPixels; float density; int densityDpi; float scaledDensity; float xdpi; float ydpi; }; void JNICALL Java_com_foobar_helloapp_JNIWrapper_load_1activity(JNIEnv * env, jclass clazz, jobject activity) { //从对象获取 class jclass classActivity = env->GetObjectClass(activity); //从 class 获取方法ID jmethodID getAssets = env->GetMethodID(classActivity, "getAssets", "()Landroid/content/res/AssetManager;"); jmethodID getWindowManager = env->GetMethodID(classActivity, "getWindowManager", "()Landroid/view/WindowManager;"); //调用对象方法 jobject assetManager = env->CallObjectMethod(activity, getAssets); //这里调用 android ndk 的方法获得 AAssetManager AAssetManager *manager = AAssetManager_fromJava(env, assetManager); //下面的代码等价于: //DisplayMetrics metrics = new DisplayMetrics(); //activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); // jobject windowManager = env->CallObjectMethod(activity, getWindowManager); jclass classWindowManager = env->GetObjectClass(windowManager); jmethodID getDefaultDisplay = env->GetMethodID(classWindowManager, "getDefaultDisplay", "()Landroid/view/Display;"); jobject display = env->CallObjectMethod(windowManager, getDefaultDisplay); jclass classDisplay = env->GetObjectClass(display); jmethodID getMetrics = env->GetMethodID(classDisplay, "getMetrics", "(Landroid/util/DisplayMetrics;)V"); //调用构造函数实例一个对象 jclass classDisplayMetrics = env->FindClass("android/util/DisplayMetrics"); jmethodID displayMetricsConstructor = env->GetMethodID(classDisplayMetrics, "<init>", "()V"); jobject displayMetrics = env->NewObject(classDisplayMetrics, displayMetricsConstructor); env->CallVoidMethod(display, getMetrics, displayMetrics); //读取 java 中的字段 DisplayMetrics dm; jfieldID idDisplayMetrics_widthPixels = env->GetFieldID( classDisplayMetrics, "widthPixels", "I"); jfieldID idDisplayMetrics_heightPixels = env->GetFieldID( classDisplayMetrics, "heightPixels", "I"); jfieldID idDisplayMetrics_density = env->GetFieldID( classDisplayMetrics, "density", "F"); jfieldID idDisplayMetrics_densityDpi = env->GetFieldID( classDisplayMetrics, "densityDpi", "I"); jfieldID idDisplayMetrics_scaledDensity = env->GetFieldID( classDisplayMetrics, "scaledDensity", "F"); jfieldID idDisplayMetrics_xdpi = env->GetFieldID(classDisplayMetrics, "xdpi", "F"); jfieldID idDisplayMetrics_ydpi = env->GetFieldID(classDisplayMetrics, "ydpi", "F"); if ( idDisplayMetrics_widthPixels ) dm.widthPixels = env->GetIntField(displayMetrics, idDisplayMetrics_widthPixels); if ( idDisplayMetrics_heightPixels ) dm.heightPixels = env->GetIntField(displayMetrics, idDisplayMetrics_heightPixels); if ( idDisplayMetrics_density ) dm.density = env->GetFloatField(displayMetrics, idDisplayMetrics_density); if ( idDisplayMetrics_densityDpi) dm.densityDpi = env->GetIntField(displayMetrics, idDisplayMetrics_densityDpi); if ( idDisplayMetrics_scaledDensity) dm.scaledDensity = env->GetFloatField(displayMetrics, idDisplayMetrics_scaledDensity); if ( idDisplayMetrics_xdpi ) dm.xdpi = env->GetFloatField(displayMetrics, idDisplayMetrics_xdpi); if ( idDisplayMetrics_ydpi ) dm.ydpi = env->GetFloatField(displayMetrics, idDisplayMetrics_ydpi); } void JNICALL Java_com_foobar_helloapp_JNIWrapper_on_1surface_1created(JNIEnv * env, jclass clazz, jobject surface) { //调用 android ndk 方法 ANativeWindow * window = ANativeWindow_fromSurface(env, surface); }