Jni

jni第一个案例

环境配置

  1. android gradle.kts
externalNativeBuild {
    cmake {
        path = file("src/main/cpp/CMakeLists.txt")
        version = "3.18.1"
    }
}
  1. CMakeLists.txt
#cmake使用的版本  最低版本
cmake_minimum_required(VERSION 3.4.1)  
# 项目名称
project("calculator")
# 库名字   以及cpp文件
# SHARED 生成动态库。 必须大写
add_library(
        "nativeTools"
        SHARED
        "calculator.cpp"
)
# 使用的库
find_library(log-lib log)
#连接到一起
target_link_libraries(
        nativeTools
        #        calculator
        ${log-lib}
)

  1. cpp代码
#include <jni.h>
#include <jni.h>
#include <string>

extern "C"
JNIEXPORT jint JNICALL
Java_com_example_calculator_jni_JniController_add(JNIEnv *env, jobject thiz, jint a, jint b) {
    // TODO: implement add()
    return a + b;
}
  1. java
public native int add(int a, int b);
  1. JNIEnv每个线程一个
  2. thiz:旨在每次有效,本身是一个localRef

类型映射

java JNI
int jint
double jdouble
boolean jboolean
String jstring

转换

  1. java->C++
const char* cstr = env->GetStringUTFChars(jstr,nullptr);
env->RealseStringUTFChars(jstr,cstr);
  1. c++->java
jstring result = env->NewStringUTF(cstr);
  1. c++->c
result.c_str()
env->NewStringUTF(nativeString);
std::string strx = "xxxxxxxxxxxxx";
env->NewStringUTF(strx.c_str());
  1. 容易出问题
for (int i = 0; i < 10000; i++) {
    jstring str = env->NewStringUTF("xxx");
}

jni局部表会溢出

jni调用java

  1. 找到class
  2. 找到方法
  3. 调用

方法的签名规则

java Jni
void test() ()V
int add() ()I
String getName() ()Ljava/lang/String
void print(String msg) (Ljava/lang/String;)V
void add(int a,String b) (ILjava/lang/String;)V

返回值类型表

Java JNI
int I
boolean Z
long J
float F
double D
String Ljava/lang/String;
void V

调用

extern "C"
JNIEXPORT void JNICALL
Java_com_example_jni_Calculator_callJava(
        JNIEnv* env,
        jobject thiz,
        jobject student) {

    jclass cls =
            env->GetObjectClass(student);

    jmethodID method =
            env->GetMethodID(
                    cls,
                    "sayHello",
                    "()V");

    env->CallVoidMethod(
            student,
            method);
}
Java返回值 JNI调用
void CallVoidMethod
int CallIntMethod
long CallLongMethod
boolean CallBooleanMethod
float CallFloatMethod
double CallDoubleMethod
String/Object CallObjectMethod

创建对象并字段操作

创建对象

找到class,获取初始化方法,创建对象

  1. 找到class
jclass cls = env->FindClass("com/example/Person");
  1. 获取方法
jmethodID constructor =
        env->GetMethodID(
                cls,
                "<init>",
                "()V");
  1. 创建对象
jobject obj =
        env->NewObject(
                cls,
                constructor);

操作字段

找到class,找到methodid,

  1. 找到class
jclass cls = env->GetObjectClass(person);
  1. 找到字段
jfieldID nameField =
            env->GetFieldID(cls, "name","Ljava/lang/String;");
  1. 读取和设置
    // 读取
    jstring name =
            (jstring) env->GetObjectField(person, nameField);

    jint age =
            env->GetIntField(person, ageField);

    // 修改
    env->SetObjectField(
            person,
            nameField,
            env->NewStringUTF("JNI Changed"));

局部变量和全局变量

方法内的都是局部变量,比如jobject obj = thiz;局部变量,如果想全局使用需要使用env->NewGlobalRef()

局部的生命周期:

  1. jni开始->创建
  2. jni结束->销毁

全局

JNI开始->创建->JNI结束->仍然存在->DeleteGlobalRef->释放

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容