Android NDK

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);
}


你可能感兴趣的:(android)