在Android平台初学JNI踩过的几个小坑(续)

来源:互联网 发布:辽宁省人工智能协会 编辑:程序博客网 时间:2024/04/29 16:35

接上一篇博客:在Android平台初学JNI踩过的几个小坑

上一篇记录了初学JNI时踩得坑,终于是在JNI层成功调用了Android 的Java API 弹出了Toast, JNI的编写格式使用了传统的方式,这一篇记录一下动态注册JNI函数的过程。

直接在代码上注释含义。

只改动了native-lib.c的代码,其它代码没有改动:

#include <jni.h>#include "MLog.h"#define TAG "NativeActivity"// 这个是实际执行业务逻辑的函数,业务逻辑和上一篇提到的没有差别,只是函数名称可以随意写JNIEXPORT void JNICALLnative_showToast(JNIEnv* env, jobject instance,jstring str) {    jclass Toast = (*env)->FindClass(env,"android/widget/Toast");    jmethodID makeText = (*env)->GetStaticMethodID(env,Toast, "makeText", "(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;");    jstring msg = (*env)->NewStringUTF(env, "太神奇了哈哈");    jobject Toast2 = (*env)->CallStaticObjectMethod(env,Toast, makeText, instance, msg);    jmethodID show = (*env)->GetMethodID(env,Toast, "show", "()V");    (*env)->CallVoidMethod(env,Toast2, show);    Android_LOG_I(TAG, "showToast:");}// 这个数组里面定义了Java中声明的native方法和JNI层方法的映射,可以声明多个函数映射,这里只写了一个static const JNINativeMethod methodTable[] ={
    // 大括号{}里面是JNINativeMethod结构体类型的数据,依次是{"Java native方法名", "Java native方法签名", "JNI对应的函数的函数指针"}    {"showToast", "(Ljava/lang/String;)V", (void*)native_showToast}};// 关联Java层和JNI层方法的逻辑,主要由jint RegisterNatives(jclass clazz, const JNINativeMethod* methods,jint nMethods)函数实现jint register_com_yolo_jnidemo_MainActivity(JNIEnv *env){    jclass MainActivity = (*env)->FindClass(env,"com/yolo/jnidemo/MainActivity");
    // 注册函数的参数(JNIEnv类型指针,Java层方法所在类,函数映射列表,函数个数)    return (*env)->RegisterNatives(env, MainActivity, methodTable, 1); }
// 该函数在System.loadLibrary()方法加载so库后回调JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved){    JNIEnv *env = NULL;    // 通过JavaVM来获取JNIEnv实例,将获取结果传给env变量    if((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_4) != JNI_OK)    {        Android_LOG_E(TAG, "get JNIEnv failed.");        return -1;    }    // 获取JNIEnv成功后就可以调用注册函数进行Java层和JNI层关联,关联成功后我们在Java层调用native方法就会执行JNI层对应函数的逻辑    register_com_yolo_jnidemo_MainActivity(env);    Android_LOG_D(TAG, "jni onload.");    return JNI_VERSION_1_4;}
// 该函数在JNI库被卸载时回调,可以执行一些清理逻辑JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved){    Android_LOG_D(TAG, "jni onunload.");}

以上函数的书写顺序是由于C代码需要先声明后使用,因此一些后执行的逻辑写在了前面,实际的执行顺序是:

JNI_OnLoad -> register_com_yolo_jnidemo_MainActivity -> methodTable -> native_showToast

在这里很希望一些同学发现问题后能指出来,将不正确的知识点完善起来,共同进步。


原创粉丝点击