Android随笔-JNI

3 篇文章 0 订阅

概述

请添加图片描述
JNI:Java Native Interface,即Java本地接口,使Java与其他类型的语言进行交互,和C/C++交互的比较多。JNI属于Java的一部分,是JDK的组成部分,和Android关系不大,但是Android中核心的业务或高性能的功能都是C/C++开发的,比如游戏渲染、音视频编解码等,所以对于Android开发,JNI也是需要了解的。Android中并不是直接和C/C++打交道,是和.so(动态库),.a(静态库)文件打交道。

创建

Android中使用JNI需要提前安装NDK,NDK(Native Development Kit)是后台Android平台提供的开发工具包,把JNI、gcc、g++…等都封装进入了,方便开发者开发。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
project:
请添加图片描述
CMakeLists.txt:
在这里插入图片描述
native-lib.cpp
在这里插入图片描述
和常规的Android项目比,大部分都一样,有些配置文件不同,还多了cpp目录,cpp目录下native-lib.cpp文件就是Java调用C/C++的地方。
CMakeLists.txt是CMake的组态档,组态档是用一种建构软件专用的特殊编程语言写的CMake脚本,CMake是CMake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的makefile或者project文件,能测试编译器所支持的C++特性,类似UNIX下的automake。

使用

规则

java中的属性和方法在C/C++中不能直接使用,需要按照一定的规则进行转换。

javaC/C++
booleanZ
byteB
charC
shortS
intI
longJ
floatF
doubleD
voidV
object objLobj
int[][I
void name(double b)(D) V

加载库

    // Used to load the 'jni' library on application startup.
    static {
        System.loadLibrary("jni");
    }

如果没有设置库名称,可以直接使用文件名。

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

创建native方法

在MainActivity中创建native方法。

   /**
     * A native method that is implemented by the 'jni' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();

native-lib.cpp中需要使用c++实现创建的native方法。

实现native方法

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_jni_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

细节解读:

  • extern “C”
    表示下面的代码都会采用C的编译方式,因为native-lib是c++文件,所以在c++文件中使用C需要单独标记一下。如果代码使用C++写的就不用使用这句话。
  • JNIEXPORT
    JNI关键字,表示该方法可以被外部调用,不同的操作系统可能不同。
  • jstring
    表示该方法的返回值是java中的String类型,若java中返回值为int,则这里为jint,若没有返回值,这里为void。
  • JNICALL
    JNI关键字,可以没有,是约束函数入栈顺序,栈和堆内存清理规则的。
  • Java_com_example_jni_MainActivity_stringFromJNI
    Java语言哪个包下,哪个类的哪个方法。
  • JNIEnv
    c和java之间相互调用的桥梁,通过它相关的操作才能起作用。
  • jobject
    java中传递过来的对象,相当于Java中的this,这里表示MainActivity。
  • NewStringUTF
    c中的属性java也不能直接使用,所以需要单独的方法进行转换,这里是转换成java可以使用的字符串。

C中修改Java的字段

Java:

 private String name;
 
 // native方法,修改name字段
 public native void  updateName();

native-lib.cpp中:

extern "C"
JNIEXPORT void JNICALL
Java_com_example_jni_MainActivity_updateName(JNIEnv *env, jobject thiz) {
    // 拿到MainActivity
    jclass mainActivityCls = env->GetObjectClass(thiz);
    // 获取属性名称及类型
    jfieldID  name_fid = env->GetFieldID(mainActivityCls,"name", "Ljava/lang/String;");
    // 设置被修改的Java的属性的值
    jstring value = env->NewStringUTF("JNI测试");
    // 赋值
    env->SetObjectField(thiz,name_fid,value);
}
  • jclass表示MainActivity.class
  • jfieldID表示name字段
  • “Ljava/lang/String;”表示name类型为String类型
  • jstring,表示创建字符串
  • SetObjectField,赋值
    整个流程走完和反射十分相似,一步一步将需要修改的内容取出来,然后进行赋值。

调用Java方法

Java:

    private int num01 = 1;
    private int num02 = 2;
    
    // java方法
    public int add(int num1,int num2){
        return num1 + num2;
    }
    // native方法
    public native int addNum();

native-lib.cpp:

extern "C"
JNIEXPORT jint JNICALL
Java_com_example_jni_MainActivity_addNum(JNIEnv *env, jobject thiz) {
    // 拿到MainActivity.class
    jclass mainActivityCls = env->GetObjectClass(thiz);
    // 获取方法
    jmethodID add_mid = env->GetMethodID(mainActivityCls,"add", "(II)I");
    // 调用方法
    env->CallIntMethod(thiz,add_mid,100,200);
}
  • GetMethodID,获取java方法。
  • “add”,需要调用的java方法的方法名。
  • “(II)I”,两个参数都为int,且返回值也为int。
  • CallIntMethod,调用java方法。
  • 100,200,调用java方法需要的参数。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值