How to Implement callback in the jni thread of Android

Source: Internet
Author: User

JNI callback refers to calling Java functions in C/C ++ code. When a callback function is executed in a C/C ++ thread, the callback fails.

One of the solutions for Android systems is:

Replace the creation of all threads in C/C ++ with the androidruntime: createjavathread function of the Creation thread in the Java layer.


Suppose there are c ++ functions:

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

The init () function creates a thread in which the Java test callback function receive must be called:

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


First, define the callback function pointer in 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;

Modify the init and thread_entry functions in C ++:

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

Then implement the callback function in JNI and Other implementations:

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

Set the shared library in the Android. mk file of JNI:

LOCAL_SHARED_LIBRARIES := liblog libcutils libandroid_runtime libnativehelper

Finally, implement the test class in Java:

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












Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.