JNI学习4.动态注册

静态注册

静态注册较为简单,只需要在Java程序中声明jni函数,随后在cpp程序中实现此jni函数即可。

public native String stringFromJNI();//声明
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_hello_1cmake_MainActivity_stringFromJNI(JNIEnv* env,jobject ){
    std::string hello = "JNI test demo";
    return env->NewStringUTF(hello.c_str());
}//实现函数

静态注册的实现方式为:当java程序第一次使用某个jni函数时,会进行搜索,根据包名-类名-函数名进行搜索,随后与对应的jni函数建立连接,随后便可以调用。

由于虚拟机自动实现了注册匹配,所以在实际编写中比较省力,名字匹配了就可以直接用。

但是静态注册有一些缺点:1.函数名称需要匹配,不能自定义。2.每个jni函数第一次被调用时都需要搜索,增加了额外开销。如果工程中的jni函数较多,在搜索方面可能会花费较多时间。

动态注册

动态注册通过手动注册实现虚拟机与jni的连接。优点是节约了搜索所需的开销,缺点是需要额外进行函数编写,增加了人工工作量。

创建一个java类,里面声明两个jni函数:

package com.example.hello_cmake;

public class TestJni {
    static {
        System.loadLibrary("native-lib");
    }

    public native int text(String message);
    public static native int static_text(String message);
}

创建一个cpp文件,代码实现如下:

#include <jni.h>
#include <string>
#include <android/log.h>
#define LOG_TAG "CPPLOG"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
//jni函数实现1
jint native_text(JNIEnv *env, jobject jobject1, jstring msg){
    const char *jmsg = env->GetStringUTFChars(msg, JNI_FALSE);
    LOGD("message = %s",jmsg);
    return 0;
}
//jni函数实现2
jint native_static_text(JNIEnv *env, jobject jobject1, jstring msg){
    const char *jmsg = env->GetStringUTFChars(msg, JNI_FALSE);
    LOGD("message = %s",jmsg);
    return 0;
}

//方法注册结构体
static const JNINativeMethod nativeMethod[] = {
        {"text",        "(Ljava/lang/String;)I", (void *) native_text},
        {"static_text", "(Ljava/lang/String;)I", (void *) native_static_text}
};

//注册函数
static int registNativeMethod(JNIEnv *env) {
    int result = -1;

    jclass class_text = env->FindClass("com/example/hello_cmake/TestJni");
    if (env->RegisterNatives(class_text, nativeMethod,
                             sizeof(nativeMethod) / sizeof(nativeMethod[0])) == JNI_OK) {
        result = 0;//返回0代表成功
    }
    return result;
}

//加载动态库
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    JNIEnv *env = NULL;
    int result = -1;

    if (vm->GetEnv((void **) &env, JNI_VERSION_1_1) == JNI_OK) {
        if (registNativeMethod(env) == JNI_OK) {
            result = JNI_VERSION_1_6;
        }
        //返回值代表动态库需要的jni版本
        return result;
    }
}



在活动中进行调用:

TestJni.static_text("it is a static method");
new TestJni().text("it is a normal method");

 代码讲解

从cpp代码中可知,为了实现动态注册,额外实现了两个函数与一个结构体。

//加载动态库
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    JNIEnv *env = NULL;
    int result = -1;

    if (vm->GetEnv((void **) &env, JNI_VERSION_1_1) == JNI_OK) {
        if (registNativeMethod(env) == JNI_OK) {
            result = JNI_VERSION_1_6;
        }
        //返回值代表动态库需要的jni版本
        return result;
    }
}

首先被调用的是JNI_OnLoad函数,该函数的返回值是需要的jni版本。

需要注意的是,该函数在jni.h中只是进行了声明,并没有被实现,因此在此处可以直接实现。

/*
 * Prototypes for functions exported by loadable shared libs.  These are
 * called by JNI, not provided by JNI.
 */
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved);
JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved);

随后被调用的是:

//注册函数
static int registNativeMethod(JNIEnv *env) {
    int result = -1;

    jclass class_text = env->FindClass("com/example/hello_cmake/TestJni");
    if (env->RegisterNatives(class_text, nativeMethod,
                             sizeof(nativeMethod) / sizeof(nativeMethod[0])) == JNI_OK) {
        result = 0;//返回0代表成功
    }
    return result;
}

该函数在JNI_OnLoad函数中被调用,该函数的目的是加载方法注册结构体,将jni函数与java里的声明进行注册链接。

该函数返回值为0时说明方法注册结构体已经加载成功。

方法注册结构体:

//方法注册结构体
static const JNINativeMethod nativeMethod[] = {
        {"text",        "(Ljava/lang/String;)I", (void *) native_text},
        {"static_text", "(Ljava/lang/String;)I", (void *) native_static_text}
};

方法注册结构体是我们自定义函数名称与建立对应关心的核心。

结构体内的成员依次是:java中声明的jni函数名称,java中声明的jni函数的函数签名,自定义实现的jni函数名称。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值