JNI接口操作最佳实践(三)「终于解决」

JNI接口操作最佳实践(三)「终于解决」前面我们介绍了JNI的常规注册方法(静态注册方法),并对JNI各种典型应用做了一个实践演练。

欢迎大家来到IT世界,在知识的湖畔探索吧!

前面我们介绍了JNI的常规注册方法(静态注册方法),并对JNI各种典型应用做了一个实践演练。本文我们介绍JNI的另一个注册方法:动态注册方法

一、静态注册

1、注册步骤

1)编写java代码和声明native 方法

2)过javah指令,自动成JNI的头文件(或者按照JNI规范手动自定义)

3)实现jni头文件里面定义的函数

2、注册原理

静态注册的原理是当加载动态库到jvm后,当Native方法第一次执行时会根据其方法名去匹配对应的C语言实现

3.优点

可以自动生成头文件,模式相对固定。

4、缺点

1)后期类名、文件名改动,头文件所有函数将失效,需要手动改,超级麻烦易出错

2)代码编写不方便,由于JNI层函数的名字必须遵循特定的格式,且名字特别长;

3)会导致程序员的工作量很大,因为必须为所有声明了native函数的java类编写JNI头文件;

4)程序运行效率低,因为初次调用native函数时需要根据根据函数名在JNI层中搜索对应的本地函数,然后建立对应关系,这个过程比较耗时。

二、动态注册

1、注册步骤

1)建立java函数和C函数映射的数组(签名必须一致)

2)通过RegisterNatives注册映射数组

3)重写JNI_OnLoad方法,动态库加载时就会调用JNI_OnLoad,注册映射数组

2、注册原理

动态注册的关键是JNINativeMethod结构体和JNI_OnLoad的实现,JNINativeMethod结构体包含:name-方法名;signature-方法签名(描述返回值和入参);fnPtr-c中实现的函数指针;JNI_OnLoad作用是绑定JNINativeMethod和class直接的关系并返回JNI的版本号。在执行JNI_OnLoad完成注册后,当java代码中执行Native方法时根据调用类可以找对应JNINativeMethod再根据方法名和方法签名可以找到对应的C语言函数指针。

3.优点
首次执行Native方法时即可根据映射关系直接获取对应的C函数指针,无需全局匹配
对C函数的实现类文件命名没有特殊要求,可以在一个文件里完成多个java文件中多个Native方法的实现和注册。增加新的JNI接口只需要增加注册数组成员,比较灵活,且效率高。

三、动态注册最佳实践

1)Java层代码

public native String GetstringFromJNI();
// Used to load the 'native-lib' library on application startup.
static {
    System.loadLibrary("jni-test");
}
private ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = ActivityMainBinding.inflate(getLayoutInflater());
    setContentView(binding.getRoot());
    // Example of a call to a native method
    TextView tv = binding.sampleText;
    tv.setText(GetstringFromJNI());
}

欢迎大家来到IT世界,在知识的湖畔探索吧!

Java代码的声明和调用与常规的静态方法时一致的。

2、Jni层代码

欢迎大家来到IT世界,在知识的湖畔探索吧!#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
GetstringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from jni test2 by dynamic load";
    return env->NewStringUTF(hello.c_str());
}
/*
 需要注册的函数列表,放在JNINativeMethod 类型的数组中,以后如果需要增加函数,只需在这⾥添加就⾏了
 参数:
 1.java中⽤native关键字声明的函数名
 2.签名(传进来参数类型和返回值类型的说明)
 3.C/C++中对应函数的函数名(地址)*/
static JNINativeMethod gMethods[] = {
        { "GetstringFromJNI", "()Ljava/lang/String;", (void*)GetstringFromJNI },//绑定
};
//此函数通过调⽤RegisterNatives⽅法来注册我们的函数
static int registerNativeMethods(JNIEnv* env, const char* className,
                                 JNINativeMethod* getMethods, int methodsNum) {
    jclass clazz;
    //找到声明native⽅法的类
    clazz = env->FindClass(className);
    if (clazz == NULL) {
        return JNI_FALSE;
    }
    //注册函数 参数:java类 所要注册的函数数组 注册函数的个数
    if (env->RegisterNatives(clazz, getMethods, methodsNum))
    {
        return JNI_FALSE;
    }
    return JNI_TRUE;
}
static int registerNatives(JNIEnv* env) {
    //指定类的路径,通过FindClass ⽅法来找到对应的类
    const char* className = "com/example/jni_test2/MainActivity";
    return registerNativeMethods(env, className, gMethods,
                                 sizeof(gMethods) / sizeof(gMethods[0]));
}
//动态注册 java通过loadLibrary 调用so库就会触发该函数加载jni库
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
    JNIEnv* env = NULL;
    //获取JNIEnv
    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
        return -1;
    }
    //注册函数 registerNatives ->registerNativeMethods ->env->RegisterNatives
    if (!registerNatives(env)) {
        return -1;
    }
    //返回jni 的版本
    return JNI_VERSION_1_6;
}

以上就是关于jni动态方法的注册,基本思路:定义方法数组—在jni_load时注册方法数组。更多更详细信息请关注微信公众号:AV_Chat

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/22783.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们YX

mu99908888

在线咨询: 微信交谈

邮件:itzsgw@126.com

工作时间:时刻准备着!

关注微信