如何在android的jni线程中实现回调
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在android的jni线程中实现回调相关的知识,希望对你有一定的参考价值。
参考技术A 您好,很高兴能帮助您如果是C/C++回调,你只要参考linux的线程指南,在线程函数中传入回调函数地址就行了。如果是要回调到Java层,稍微复杂点。
首先,你需要在onload的时候,找到回调函数所在的类,用全局变量保存:
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
LOGE("JNI_OnLoad start");
jint version;
g_vm = vm; // 全局变量保存
JNIEnv *env;
jobject cls;
version = vm->GetEnv((void **)&env, JNI_VERSION_1_2);
if (env)
g_clazz = env->FindClass(CLASS_CustomSurfaceView); // 全局变量保存
LOGE("JNI_OnLoad finish g_clazz = 0x%x", g_clazz);
return JNI_VERSION_1_2;
在JNI启动线程的时候,需要把线程挂到JVM上,不然不能访问Java。你有了g_vm, g_clazz, 以及env,就可以做回调操作了。
// 线程函数
void *threadFunc(void *data)
JNIEnv *env = MNull;
int ret = g_vm->AttachCurrentThread( (JNIEnv **) &env, MNull); // 挂到JVM
if (ret < 0)
LOGE("fail to attach");
return;
// TODO: 在这里做你的回调操作
g_vm->DetachCurrentThread(); // 从JVM卸载
return;
你的采纳是我前进的动力,
记得好评和采纳,答题不易,互相帮助,本回答被提问者和网友采纳 参考技术B JNI回调是指在c/c++代码中调用java函数,当在c/c++的线程中执行回调函数时,会导致回调失败。
其中一种在android系统的解决方案是:
把c/c++中所有线程的创建,由pthread_create函数替换为由Java层的创建线程的函数AndroidRuntime::createJavaThread。
假设有c++函数:
[cpp] view plaincopy
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:
[cpp] view plaincopy
public void Receive(char buffer[],int length)
String msg = new String(buffer);
msg = "received from jni callback:" + msg;
Log.d("Test", msg);
首先在c++中定义回调函数指针:
[cpp] view plaincopy
//test.h
#include <pthread.h>
//function type for receiving data from native
typedef 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函数:
[cpp] view plaincopy
//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 java
if(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中实现回调函数,以及其他实现:
[cpp] view plaincopy
//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 array
for(i = 0; i < len; i++)
*(pArray + i) = *(buf + i);
//copy buffer to jcharArray
env->SetCharArrayRegion(array,0,len,pArray);
//invoke java callback method
env->CallVoidMethod(mCallbacksObj, method_receive,array,len);
//release resource
env->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文件中共享库设置为:
[cpp] view plaincopy
LOCAL_SHARED_LIBRARIES := liblog libcutils libandroid_runtime libnativehelper
最后再实现Java中的Test类:
[java] view plaincopy
//com.tonny.Test.java
public 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线程中实现回调的主要内容,如果未能解决你的问题,请参考以下文章