歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Android NDK 線程回調Java層方法

項目上剛好要在Android NDK層使用線程回調Java層方法,僅以此文做個總結。線程使用pthread創建(在此略過),線程會循環調用NofityDataCB函數:

static JavaVM* s_jVM = NULL;
static jobject s_jobj = NULL; //java object
static jmethodID s_jcallback = NULL; //方法id

static void NotifyDataCB(unsigned char flag, int x, int y, int w, int h, unsigned char* buff, mp_i64 timeStamp)
{
 //LOG_DBG("[NotifyDataCB()] enter.");
 JNIEnv* env;

 s_jVM->AttachCurrentThread(&env, NULL); //獲取當前線程的JNIEnv*

 env->CallVoidMethod(s_jobj, s_jcallback, ...); //調用java層相關方法

 s_jVM->DetachCurrentThread(); //釋放當前線程的JNIEnv*

 //LOG_DBG("[NotifyDataCB()] done.");
 return;
}

此處的重點即為:

jint AttachCurrentThread(JavaVM *vm, void **p_env, void *thr_args);

Attaches the current thread to a Java VM. Returns a JNI interface pointer in the JNIEnv argument.

其中s_jVM是由JNI_OnLoad方法保存而來的;

s_jobj在自定義的jni方法裡賦值,並創建了個全局引用,使其不被虛擬機釋放

s_jobj = env->NewGlobalRef(thiz); //thiz為jni方法的參數,表示java層的類對象

該s_jobj需要手動釋放:

env->DeleteGlobalRef(s_jobj);

s_jcallback也是在自定義的jni方法調用以下方法保存而來:

static jmethodID GetClassMethodID(JNIEnv* env)
{
 jclass clazz = env->FindClass(classPathName); //classPathName完整的包名加類名
 if (clazz == NULL)
 {
  LOG_ERR("[GetClassMethod()]Failed to find jclass");
  return NULL; 
 }


 jmethodID jcallback = env->GetMethodID(clazz, "OnNativeDataCB", "(BIIII[IJ)V"); //獲取java層方法id
 if (jcallback == NULL)
 {
  LOG_ERR("[GetClassMethod()]Failed to find method OnNativeDataCB");
  return NULL; 
 }
 
 return jcallback; //返回保存為s_jcallback
}

綜上所述,關鍵步驟為:
1. 在onload的時候保存JavaVM指針。
2. 在自定義jni方法裡(該方法須在callback方法使用前調用,例如初始化方法)保存callback方法所在對象,且該對象需要創建一個全局引用以便在線程方法裡使用,默認是local ref,函數執行完會被虛擬機釋放;另外自定義jni方法和callback方法在同一個類裡,所以在調用自定義方法時能保存一致的jobject  。
3. 也是在自定義jni方法中,通過class獲得該callback的method ID。

更多Android相關信息見Android 專題頁面 http://www.linuxidc.com/topicnews.aspx?tid=11

Copyright © Linux教程網 All Rights Reserved