如何在android的jni線程中實現回調

來源:互聯網
上載者:User

JNI回調是指在c/c++代碼中調用java函數,當在c/c++的線程中執行回呼函數時,會導致回調失敗。

其中一種在Android系統的解決方案是:

把c/c++中所有線程的建立,由pthread_create函數替換為由Java層的建立線程的函數AndroidRuntime::createJavaThread。


假設有c++函數:

void *thread_entry(void *args){while(1){printf("thread running...\n");sleep(1);}}void init(){pthread_t thread;pthread_create(&thread,NULL,thread_entry,(void *)NULL);}

init()函數建立一個線程,需要在該線程中調用java類Test的回呼函數Receive:

public void Receive(char buffer[],int length){String msg = new String(buffer);msg = "received from jni callback:" + msg;Log.d("Test", msg);}


首先在c++中定義回呼函數指標:

//test.h#include <pthread.h>//function type for receiving data from nativetypedef void (*ReceiveCallback)(unsigned char *buf, int len);/** Callback for creating a thread that can call into the Java framework code. *  This must be used to create any threads that report events up to the framework. */typedef pthread_t (* CreateThreadCallback)(const char* name, void (*start)(void *), void* arg);typedef struct{ReceiveCallback recv_cb;CreateThreadCallback create_thread_cb;}Callback;

再修改c++中的init和thread_entry函數:

//test.c#include <stdio.h>#include <stdlib.h>#include <pthread.h>#include <sys/wait.h>#include <unistd.h>#include "test.h"void *thread_entry(void *args){char *str = "i'm happy now";Callback cb = NULL;int len;if(args != NULL){cb = (Callback *)args;}len = strlen(str);while(1){printf("thread running...\n");//invoke callback method to javaif(cb != NULL && cb->recv_cb != NULL){cb->recv_cb((unsigned char*)str, len);}sleep(1);}}void init(Callback *cb){pthread_t thread;//pthread_create(&thread,NULL,thread_entry,(void *)NULL);if(cb != NULL && cb->create_thread_cb != NULL){cb->create_thread_cb("thread",thread_entry,(void *)cb);}}

然後在jni中實現回呼函數,以及其他實現:

//jni_test.c#include <stdlib.h>#include <malloc.h>#include <jni.h>#include <JNIHelp.h>#include "android_runtime/AndroidRuntime.h"#include "test.h"#define RADIO_PROVIDER_CLASS_NAME "com/tonny/Test"using namespace android;static jobject mCallbacksObj = NULL;static jmethodID method_receive;static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {    if (env->ExceptionCheck()) {        LOGE("An exception was thrown by callback '%s'.", methodName);        LOGE_EX(env);        env->ExceptionClear();    }}static void receive_callback(unsigned char *buf, int len){int i;    JNIEnv* env = AndroidRuntime::getJNIEnv();jcharArray array = env->NewCharArray(len);jchar *pArray ;if(array == NULL){LOGE("receive_callback: NewCharArray error.");return; }pArray = (jchar*)calloc(len, sizeof(jchar));if(pArray == NULL){LOGE("receive_callback: calloc error.");return; }//copy buffer to jchar arrayfor(i = 0; i < len; i++){*(pArray + i) = *(buf + i);}//copy buffer to jcharArrayenv->SetCharArrayRegion(array,0,len,pArray);//invoke java callback method    env->CallVoidMethod(mCallbacksObj, method_receive,array,len);//release resourceenv->DeleteLocalRef(array);free(pArray);pArray = NULL;    checkAndClearExceptionFromCallback(env, __FUNCTION__);}static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg){    return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);}static Callback mCallbacks = {receive_callback,create_thread_callback};static void jni_class_init_native(JNIEnv* env, jclass clazz){method_receive = env->GetMethodID(clazz, "Receive", "([CI)V");}static int jni_init(JNIEnv *env, jobject obj){if (!mCallbacksObj)mCallbacksObj = env->NewGlobalRef(obj);return init(&mCallbacks);}static const JNINativeMethod gMethods[] = {  { "class_init_native","()V",(void *)jni_class_init_native },    { "native_init","()I",(void *)jni_init },};  static int registerMethods(JNIEnv* env) {  const char* const kClassName = RADIO_PROVIDER_CLASS_NAME;    jclass clazz;     /* look up the class */      clazz = env->FindClass(kClassName);      if (clazz == NULL) {          LOGE("Can't find class %s/n", kClassName);          return -1;      }  /* register all the methods */      if (env->RegisterNatives(clazz,gMethods,sizeof(gMethods)/sizeof(gMethods[0])) != JNI_OK)      {          LOGE("Failed registering methods for %s/n", kClassName);          return -1;      }  /* fill out the rest of the ID cache */      return 0;  }   jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = NULL;  jint result = -1;  LOGI("Radio JNI_OnLoad");      if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {      LOGE("ERROR: GetEnv failed/n");      goto fail;  }  if(env == NULL){goto fail;}if (registerMethods(env) != 0) {     LOGE("ERROR: PlatformLibrary native registration failed/n");      goto fail;  }  /* success -- return valid version number */      result = JNI_VERSION_1_4;  fail:  return result;  } 

jni的Android.mk檔案中共用庫設定為:

LOCAL_SHARED_LIBRARIES := liblog libcutils libandroid_runtime libnativehelper

最後再實現Java中的Test類:

//com.tonny.Test.javapublic class Test {static{try {System.loadLibrary("test");class_init_native();} catch(UnsatisfiedLinkError ule){            System.err.println("WARNING: Could not load library libtest.so!");        }}public int initialize() {return native_radio_init();}public void Receive(char buffer[],int length){String msg = new String(buffer);msg = "received from jni callback" + msg;Log.d("Test", msg);}protected  static native void class_init_native();protected  native int native_init();}












聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.