IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Android NDK学习笔记-JNI访问Java属性、方法 -> 正文阅读

[Java知识库]Android NDK学习笔记-JNI访问Java属性、方法

转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/119209444
本文出自【赵彦军的博客】

Java 类型和JNI符号对比

对应基础类型字段的转换:

Java 类型JNI符号
BooleanZ
ByteB
CharC
ShortS
IntI
LongJ
FloatF
DoubleD

对于引用类型的字段签名转换,是大写字母 L 开头,然后是类的签名转换,最后以 ; 结尾。

Java 类型JNI符号
StringLjava/lang/String;
ClassLjava/lang/Class;
ThrowableLjava/lang/Throwable;
int[][I
Object[][Ljava/lang/Object;

对于方法签名描述的转换,首先是将方法内所有参数转换成对应的字段描述,并全部写在小括号内,然后在小括号外再紧跟方法的返回值类型描述。

Java 类型JNI 对应的描述转换
String f();()Ljava/lang/String;
long f(int i, Class c);(ILjava/lang/Class;)J
String(byte[] bytes);([B)V

这里要注意的是在 JNI 对应的描述转换中不要出现空格。

JNI 访问属性

创建 Util.java 类

/**
 * @author : zhaoyanjun
 * @time : 2021/7/29
 * @desc :
 */
public class Util {

    String usernName = "zhaoyanjun";
    int age = 10;
    static float key = 2f;

    //修改类string属性
    native void changeNameValue();

    //修改类int属性
    native void changeAgeValue();

    //改变静态变量值
    native void changeStaticValue();
}

访问 String 属性、int 属性

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val util = Util()
        util.changeNameValue()  //修改string
        util.changeAgeValue()   //修改int
        util.changeStaticValue()  //修改静态变量
        binding.sampleText.text = "value:${util.usernName} ${util.age} ${Util.key}"

    }

    companion object {

        // Used to load the 'native-lib' library on application startup.
        init {
            System.loadLibrary("native-lib")
        }
    }
}

native-lib.cpp

//修改字符串属性
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_Util_changeNameValue(JNIEnv *env, jobject thiz) {
    //获取class
    jclass cls = env->GetObjectClass(thiz);
    //获取字段
    jfieldID fid = env->GetFieldID(cls, "usernName", "Ljava/lang/String;");
    //创建新值
    jstring str = env->NewStringUTF("niu b");
    //给字段赋值
    env->SetObjectField(thiz, fid, str);
}

//修改int属性
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_Util_changeAgeValue(JNIEnv *env, jobject thiz) {
    //获取class
    jclass cls = env->GetObjectClass(thiz);
    //获取字段
    jfieldID fid = env->GetFieldID(cls, "age", "I");
    //给字段赋值
    env->SetIntField(thiz, fid, 100);
}

//修改静态属性
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_Util_changeStaticValue(JNIEnv *env, jobject thiz) {
    //获取class
    jclass cls = env->GetObjectClass(thiz);
    //获取字段
    jfieldID fid = env->GetStaticFieldID(cls, "key", "F");
    //获取静态字段值
    jfloat value = env->GetStaticFloatField(cls, fid);

    //给字段赋值
    env->SetStaticFloatField(cls, fid, value + 100);
}

运行起来,看看效果
在这里插入图片描述
值已经改变。

native方法,非晶态和静态区别

Util.java

public class Util {

    native void fun1();

    native static void fun2();
}

native-lib.cpp

//非静态方法
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_Util_fun1(JNIEnv *env, jobject thiz) {

}

//静态方法
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_Util_fun2(JNIEnv *env, jclass clazz) {
    
}

可以看到,非静态方法,参数是 jobject; 静态方法,参数是jclass

多种方式获得 jclass

extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_Util_fun1(JNIEnv *env, jobject thiz) {
    //方式一:FindClass,参数传入类全路径
    jclass cls = env->FindClass("com/example/myapplication/Util");
    
    //方式二:GetObjectClass
    jclass cls2 = env->GetObjectClass(thiz);
}

JNI 方法Java方法

无参无返回值

/**
 * @author : zhaoyanjun
 * @time : 2021/7/29
 * @desc :
 */
public class Util {

    void run() {
        Log.d("util-", "runing");
    }

    String speak(String message) {
        Log.d("util-", "speak " + message);
        return message + " java";
    }

    //无参无返回值
    native void callRun();
}

native-lib.cpp

extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_Util_callRun(JNIEnv *env, jobject thiz) {
    //获取jclass
    jclass cls = env->GetObjectClass(thiz);
    //获取方法
    jmethodID method = env->GetMethodID(cls, "run", "()V");
    //调用方法
    env->CallVoidMethod(thiz, method);
}

无参符号:() , 无返回值符号:V , 结合起来就是 ()V

有参数有返回值

native String callSpeak();

native-lib.cpp

//调用带有
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_myapplication_Util_callSpeak(JNIEnv *env, jobject thiz) {
    //获取jclass
    jclass cls = env->GetObjectClass(thiz);
    //获取方法
    jmethodID method = env->GetMethodID(cls, "speak", "(Ljava/lang/String;)Ljava/lang/String;");
    
    jstring str = env->NewStringUTF("jni hello");
    //方法调用,并接收返回值
    jobject result = env->CallObjectMethod(thiz, method, str);
    //返回结果
    return static_cast<jstring>(result);
}

静态方法

方式1:非静态 native 方法

public class Util {

    static void run() {
        Log.d("util-", "runing");
    }

    native void callRun();
}

native-lib.cpp

extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_Util_callRun(JNIEnv *env, jobject thiz) {
    jclass cls = env->GetObjectClass(thiz);
    jmethodID method = env->GetStaticMethodID(cls, "run", "()V");
    env->CallStaticVoidMethod(cls, method);
}

调用:

val util = Util()
util.callRun()

需要注意的是

  • 获取静态方法用 GetStaticMethodID
  • 调用静态方法用 CallStaticVoidMethod

方式2:静态 native 方法

public class Util {

    static void run() {
        Log.d("util-", "runing");
    }

    //静态的
    native static void callRun();
}

native-lib.cpp

extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_Util_callRun(JNIEnv *env, jclass clazz) {
    jmethodID method = env->GetStaticMethodID(clazz, "run", "()V");
    env->CallStaticVoidMethod(clazz, method);
}

调用:

 Util.callRun()

需要注意的是:静态的 native 方法,必须用 类名调用。非静态的 nativie方法,需要用对象调用。

实战演练: 调用Android Log

我们首先来看系统Log类
在这里插入图片描述
要确认两点信息
第一:类的包名是:android.util
第二:d() 方法,两个参数,都是 String 类型。返回值是 int

下面我们就可以写代码了。

首先创建 native 方法,有两个参数,一个是 tag , 一个是 message

public class Util {

    //静态的
    native static void logd(String tag, String message);

}

native-lib.cpp

extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_Util_logd(JNIEnv *env, jclass clazz, jstring tag, jstring message) {

    //获取Log class
    jclass cls = env->FindClass("android/util/Log");

    //获取 d() 方法
    jmethodID method = env->GetStaticMethodID(cls, "d",
                                              "(Ljava/lang/String;Ljava/lang/String;)I");
    
    //调用方法
    env->CallStaticIntMethod(cls, method, tag, message);
}

具体使用:

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        //调用c++输出日志
        Util.logd("china--", "good")
    }

    companion object {

        // Used to load the 'native-lib' library on application startup.
        init {
            System.loadLibrary("native-lib")
        }
    }
}
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-07-30 22:41:08  更:2021-07-30 22:41:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/2 0:21:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码