如何在android的jni线程中实现回调
分类: C/C++ Android 2012-03-16 11:38 711人阅读 评论(2) 收藏 举报
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进行多线程编程,并实现native方法对Java函数的回调。 1. **JNI基础知识**: - JNI是Java平台的一部分,为Java应用程序提供了与本地代码交互的能力。开发者可以通过JNI在...
JNI调用比较简单,根据JNI给出的实例,本内容主要讲多线程使用回调步骤:主要说明参照我的博文 http://blog.csdn.net/inr12345/article/details/8935350
多线程回调Java方法在JNI层实现,能够帮助我们优化程序执行效率,特别是在处理耗时操作如图像处理、音频视频解码等场景。 本文将深入探讨如何在JNI层实现多线程回调Java方法,以及如何解决在C/C++层多线程环境下...
在Android开发中,JNI(Java Native Interface)是一个关键的技术,它允许...通过分析和学习这个示例,你可以更好地理解JNI线程回调的实现细节。在实际项目中,理解并掌握这些知识对于提高程序的性能和稳定性至关重要。
“JniCallback.zip”中的“JniCallback”文件可能是一个示例项目,展示了如何在Android应用中实现JNI回调。这个项目可能包含了一个Java类,该类定义了回调接口,以及对应的本地代码实现,演示了如何在本地代码中...
本教程将详细介绍如何在Android中使用JNI实现C语言回调Java的方法,包括有参无参、有无返回值以及静态非静态函数的不同情况。 1. **JNI基础概念** JNI是Java平台的标准组成部分,它提供了一套接口,使得Java代码...
例如,你可以创建一个方法来启动一个新的线程,并传入一个回调函数,这个函数将在新线程中被调用。 2. **生成JNI头文件**:使用`javah`工具(或者在Android Studio中自动完成)根据你的Java类生成对应的C/C++头文件...
JNI(Java Native Interface)是Java平台提供的一种标准接口,它允许Java代码和其他语言写的代码进行交互。...在实际应用中,合理运用JNI回调可以提高性能,实现复杂功能,但也需要注意其带来的额外复杂性。
综上所述,JNI回调函数Callback是Android开发中连接Java和C/C++的重要方式,它使得两个世界之间的通信更为灵活,能够实现更多复杂的逻辑。在实际应用中,开发者需要熟练掌握JNI的基础知识,并了解如何安全有效地使用...
在Android开发中,JNI(Java Native Interface)是一种技术,允许Java代码和其他编程语言(如C++)进行交互。JNI在很多场景下都很有用,比如优化性能、调用系统底层库或者像本例中那样,利用C/C++库来实现特定功能。...
例如,如果你有一个线程或者回调需要长期保留Java对象,全局引用就非常有用。 创建全局引用的步骤如下: 1. 首先,你需要一个对Java对象的本地引用,通常通过`env->GetObjectField`或`env->CallObjectMethod`等...
"hello-jniCallback"是一个常见的示例项目,用于演示如何在Android应用中使用JNI来调用C/C++代码,并实现回调机制。这个项目可以帮助开发者理解JNI的基本用法以及如何在Java和原生代码之间传递数据。 1. **JNI基础...
如果选择异步回调,那么在C/C++库中设置事件监听,并通过JNI回调Java层的函数,通知Java应用有新的数据可读或发送完成。 在描述中提到的`serial`文件可能包含了实现这些功能的源代码,如`SerialPort.c`或`...
Android JNI(Java Native Interface)开发是将Java代码与C/C++原生代码集成的一种技术,它允许开发者在Android应用中利用C/C++的高性能和低级别控制能力。本Demo是基于实际项目经验的总结,旨在展示JNI的核心用法和...
总结起来,"Android JNI Demo"是一个实践教程,旨在教会开发者如何在Android应用中使用JNI技术,结合C/C++代码提高应用性能,调用本地库,以及实现更复杂的计算任务。通过这个示例,开发者可以深入理解JNI的工作原理...
同时,为了保证线程安全,通常会使用线程或异步回调来处理串口的读写操作。 7. **数据传输**:通过JNI的`writeDataToSerialPort()`函数,可以将Java层的数据转换为字节流并发送到串口;而`readDataFromSerialPort()...
5. **线程安全**:由于Java和C/C++的线程模型不同,因此在JNI编程中需要特别注意线程同步问题。教程会介绍如何在本地代码中正确地管理和同步Java对象。 6. **回调机制**:JNI支持Java方法回调到本地代码,这对于...
本文将深入探讨在Android中如何使用JNI,特别是如何从C++ native代码调用Java层的类、方法、属性以及接口,同时涉及线程回调接口的实现。 首先,我们需要了解JNI的基本结构。一个典型的JNI应用会包含Java源文件、C/...
本篇文章将详细介绍如何在Android NDK开发中实现C回调Java中的方法。 首先,了解NDK和JNI的基础概念是必要的。NDK是一套工具,提供了在Android平台上编译和运行C/C++代码的环境。而JNI是Java平台的标准接口,它允许...