如何在android的jni线程中实现回调
来源:互联网 发布:linux系统启动命令 编辑:程序博客网 时间:2024/04/29 21:44
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();}
- 如何在android的jni线程中实现回调
- 如何在android的jni线程中实现回调
- 如何在android的jni线程中实现回调
- 如何在android的jni线程中实现回调
- 如何在android的jni线程中实现回调
- [JNI]如何在ANDROID JNI 的C++中打Log
- 如何在JNI中使用线程
- 如何在ANDROID JNI 的C++中打Log
- 如何在ANDROID JNI 的C++中打Log
- 如何在ANDROID JNI 的C++中打Log
- 如何在ANDROID JNI 的C++中打Log
- 如何在ANDROID JNI 的C++中打Log
- 如何在ANDROID JNI 的C++中打Log
- 如何在ANDROID JNI 的C++中打Log
- 如何在ANDROID JNI 的C++中打Log
- 如何在Android jni 的c/c++中打Log
- 如何在ANDROID JNI 的C++中打Log
- 如何在ANDROID JNI 的C++中打Log
- KVC and KVO
- 要成功,你只需要做好两件事情----do things , tell people
- Iphone隐藏键盘代码
- java与c/c++之间的数据交互
- SQL除法运算保留小数位
- 如何在android的jni线程中实现回调
- jQuery学习笔录4(jQuery学习笔记——DOM【2.CSS DOM】)
- Apache和tomcat整合及配置多个项目
- linux设备驱动:poll和sellct
- size_type
- jsoup 实现在自己的网站中 抓取到 其他网站对自己感兴趣的信息
- Rpc远程过程调用
- 单链表
- 一些常用的sql语句