您的位置:首页 > 移动开发 > Android开发

Android JNI使用总结(二)

2015-10-13 23:53 429 查看
上一篇里面主要是JNI中一些函数的介绍,这篇博客就举个例子来说明这些函数的使用方法。

项目介绍

这个例子来源于我实际的项目。这段代码的作用是:

通过Uart发送消息;

接受Uart传送过来的消息;

因为这里的主要目的不是说明如何使用uart,所以我的这段代码中发送是通过调用下面的方法实现的:

int uart_send(
message *callmsg, // 待发送的消息
message *retmsg, // 发送消息之后的返回值
unsigned timeout // 发送超时
);


接受是通过注册回调函数实现的。当uart处理机接受到消息之后,将调用我的回调函数。回调函数将消息处理后返回给java层的代码。

声明几个宏。

#define FIND_CLASS(var, className) \
var = env->FindClass(className); \
LOG_FATAL_IF(! var, "Unable to find class " className);

#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
var = env->GetMethodID(clazz, methodName, methodDescriptor); \
LOG_FATAL_IF(! var, "Unable to find method " methodName);

#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
LOG_FATAL_IF(! var, "Unable to find field " fieldName);


这几个宏是我在framework/base/service/jni中找到的,挺好用的。

声明全局变量。

static struct
{
jmethodID recvMsgFromNative; // 这里将存储java类UartManagerService中的方法recvMsgFromNative的ID。
} gUartManagerServiceClassInfo;

static jobject gUartManagerServiceObj; // 这个对象将存储UartManagerService对象的实例。
static jclass gUartManagerServiceClass; // 这个东西将存储UartManagerService的class。
static JavaVM * gJavaVM; // 这个就是我在上一遍博文的最后提到的全局的JavaVM对象,在必要的时候,将通过这个对象获取JNIEnv指针。


声明native方法。

static JNINativeMethod gUartManagerServiceMethods[] =
{
/* name, signature, funcPt */
{ "nativeTest", "()V", (void*) nativeTest },
{ "nativeInit", "()V", (void*) nativeInit }
};


注册native方法。

int register_android_server_iflytek_uartmanagerservice(JNIEnv* env)
{
int res = jniRegisterNativeMethods(env,
"com/android/server/iflytek/UartManagerService",
gUartManagerServiceMethods, NELEM(gUartManagerServiceMethods) );
if(res < 0)
ALOGD("Unable to register native methods.");

env->GetJavaVM(&gJavaVM);

return 0;
}


本地初始化。

static void nativeInit(JNIEnv* env, jobject obj)
{
ALOGD("nativeInit() is called");

// 获取UartManagerService对象的实例
gUartManagerServiceObj = env->NewGlobalRef(obj);

// Callbacks
FIND_CLASS(gUartManagerServiceClass, "com/android/server/iflytek/UartManagerService");

GET_METHOD_ID(gUartManagerServiceClassInfo.recvMsgFromNative, gUartManagerServiceClass,
"recvMsgFromNative", "([I)V");

// 注册回调
set_callback(get_msg_cb);
}


这个函数时在UartManagerService里调用的,所以刚好可以用来获取UartManagerService的实例。

实现发送代码。

static void nativeTest(JNIEnv* env, jobject obj)
{
ALOGD("nativeTest() is called");
message callmsg;
message retmsg;

// 循环发送1000次
for (int i = 0; i < 1000; ++ i)
{
// 填充callmsg
// ……
//

uart_send(&callmsg, &retmsg, 200);
}
}


实现接收的回调。

回调函数的参数是message结构体,而java中的回调函数的参数是int数组,所以这里要新建数组并填内容。

void get_msg_cb(message *evtmsg)
{
ALOGD("get_msg_cb() is called");
int i;

JNIEnv* env;
gJavaVM->AttachCurrentThread(&env, NULL); // 这里就是上一篇博文的最后提到的“在需要的时候”。因为这里没有JNIEnv指针,所以只能从gJavaVM中重新获取。

if(env == NULL){
ALOGD("JNIEnv is null");
return;
}

jintArray returnArray = env->NewIntArray(len);
int * pArray = (int*)malloc(sizeof(int) * len);

// 给本地数组赋值
pArray[0] = ……;
pArray[1] = ……;
for(i = 0; i < len; i++)
{
pArray[2+i] = evtmsg->data[i];
}

// 将值赋给返回值
env->SetIntArrayRegion(returnArray, 0, len + 2, pArray);

// 调用java中的函数
if(gUartManagerServiceObj != NULL){
env->CallVoidMethod(gUartManagerServiceObj, gUartManagerServiceClassInfo.recvMsgFromNative, returnArray);
}

// 释放内存
free(pArray);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: