Android JNI使用总结(二)

版权声明:本文为博主原创文章,未经博主允许不得转载。作者:Timothy,主页:http://blog.csdn.net/wtianok。 https://blog.csdn.net/wtianok/article/details/49107977

上一篇里面主要是JNI中一些函数的介绍,这篇博客就举个例子来说明这些函数的使用方法。

项目介绍

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

  1. 通过Uart发送消息;
  2. 接受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);
}
阅读更多
换一批

没有更多推荐了,返回首页