JNI 接口回调
这里主要演示从 Java 层传入自定义listener,然后由 c/c++ 层在某一时期某一线程主动调用 listener 的回调函数,完成异步回调的功能。
关于 jni 的其他部分基础知识本文不做详细介绍。
Java 层定义代码
-
java-native 函数以及接口定义
package com.jnidemo; public class Greet { static { System.loadLibrary("jni_demo"); } public native void native_say_hello(GreetListener listener); public interface GreetListener { /** * 这里为了演示自定义 Callback 的用法,使用了自定义 Java-Callback 类作为回调参数, * 可直接使用基本类型或者其他引用类型做回调参数,根据自己的业务需求决定。 */ void onGreetReceive(GreetCallback greet); } }
-
java 自定义 Callback 类
package com.jnidemo; public class GreetCallback { private int greetID; private String greetMsg; public GreetCallback(int greetID, String greetMsg) { this.greetID = greetID; this.greetMsg = greetMsg; } }
c++ 层实现代码
-
动态注册 native 实现函数
const char *NATIVE_GREET_CLASS_NAME = "com/jnidemo/Greet"; static JNINativeMethod gMethods_Greet[] = { {"native_say_hello", "(Lcom/jnidemo/Greet$GreetListener;)V", (void *)say_hello_jni} }; static int registerNativeMethods(JNIEnv *env) { jclass clazz = env->FindClass(NATIVE_GREET_CLASS_NAME); if (clazz == NULL) return JNI_FALSE; if (env->RegisterNatives(clazz, gMethods_Greet, sizeof(gMethods_Greet) / sizeof(gMethods_Greet[0])) < 0) return JNI_FALSE; env->DeleteLocalRef(clazz); clazz = NULL; return JNI_TRUE; } jint JNI_OnLoad(JavaVM *vm, void *reserved) { JNIEnv *env = NULL; if (vm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) return -1; assert(env != NULL); if (!registerNativeMethods(env)) return -1; hover_jvm = vm; return JNI_VERSION_1_6; }
-
native 函数实现
typedef struct { jobject o_greet_listener; jmethodID m_greet_receive; jclass z_greet_callback; jmethodID m_greet_callback_init; } jni_callback_t; // 定义承载 Java-Listener 和 Java-Callback 实例和 methodID 的结构体实例 static jni_callback_t *jni_callback; /** * jni 动态注册对应的 native 实现函数。 * 创建 Java-Listener 和 Java-Callback 的实例和 methodID 并赋值给 jni_callback_t. */ static void say_hello_jni(JNIEnv *env, jobject object, jobject greet_listener) { if(!greet_listener) return; // 获得回调接口 函数onGreetReceive 的 methodID. jclass clazz_greet_listener = env->GetObjectClass(greet_listener); jmethodID method_greet_receive = env->GetMethodID(clazz_greet_listener, "onGreetReceive", "(Lcom/jnidemo/GreetCallback;)V"); // 获得自定义 Callback类 GreetCallback 构造函数的 methodID. jclass clazz_greet_callback = env->FindClass("com/jnidemo/GreetCallback"); jmethodID method_greet_callback_init = env->GetMethodID(clazz_greet_callback, "<init>", "(ILjava/lang/String;)V"); // 这里创建 jni_callback_t 的实例,创建 Listener 和 Callback 的全局引用并赋值. jni_callback = (jni_callback_t *)malloc(sizeof(jni_callback_t)); memset(jni_callback, 0, sizeof(jni_callback_t)); jni_callback->o_greet_listener = env->NewGlobalRef(greet_listener); jni_callback->m_greet_receive = method_greet_receive; jni_callback->z_greet_callback = (jclass)env->NewGlobalRef(clazz_greet_callback); jni_callback->m_greet_callback_init = method_greet_callback_init; // 销毁局部引用 env->DeleteLocalRef(clazz_greet_listener); env->DeleteLocalRef(clazz_greet_callback); clazz_greet_listener = NULL; clazz_greet_callback = NULL; // 这里创建子线程模拟异步回调 pthread_t ntid; pthread_create(&ntid, NULL, async_thread_func, NULL); }
-
native 端子线程模拟回调
void *async_thread_func(void *args) { // JNI_OnLoad 时保存 jvm,这里使用 jvm->AttachCurrentThread 获取 JNIEnv,暂不做详细介绍. JNIEnv *env = NULL; hover_attach_jni_env(&env); // 使用 java 构造函数生成 GreetCallback 的实例 int greetID = 1; jstring greetMsg = env->NewStringUTF("say hi to java."); jobject greet_callback = env->NewObject(jni_callback->z_greet_callback, jni_callback->m_greet_callback_init, greetID, greetMsg); // 调用 GreetListener 的 onGreetReceive 函数,完成调用流程. env->CallVoidMethod(jni_callback->o_greet_listener, jni_callback->m_greet_receive, greet_callback); // 销毁局部引用 env->DeleteLocalRef(greetMsg); env->DeleteLocalRef(greet_callback); greetMsg = NULL; greet_callback = NULL; // 销毁全局引用 --- 如果有多处或多次回调,自行判断销毁时机. env->DeleteGlobalRef(jni_callback->o_greet_listener); env->DeleteGlobalRef(jni_callback->z_greet_callback); jni_callback->o_greet_listener = NULL; jni_callback->z_greet_callback = NULL; free(jni_callback); jni_callback = NULL; return 0; }
Java 层调用 native 函数
new Greet().native_say_hello(new Greet.GreetListener() {
@Override
public void onGreetReceive(GreetCallback greet) {
Log.d(TAG, "hello, onGreetReceive: " + greet.toString());
}
});