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

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

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

直接在代码上注释含义。

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

#include <jni.h>
#include "MLog.h"

#define TAG "NativeActivity"

// 这个是实际执行业务逻辑的函数,业务逻辑和上一篇提到的没有差别,只是函数名称可以随意写
JNIEXPORT void JNICALL
native_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

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值