JNI 接口回調

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());
          }
  });
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章