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

文章目录

  • Java 类型和JNI符号对比
  • JNI 访问属性
  • native方法,非晶态和静态区别
  • 多种方式获得 jclass
  • JNI 方法Java方法
    • 无参无返回值
    • 有参数有返回值
    • 静态方法
      • 方式1:非静态 native 方法
      • 方式2:静态 native 方法
  • 实战演练: 调用Android Log
  • 实战演练: 弹 Toast
  • 实战演练:数组传值

Java 类型和JNI符号对比

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

Java 类型 JNI符号
Boolean Z
Byte B
Char C
Short S
Int I
Long J
Float F
Double D

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

Java 类型 JNI符号
String Ljava/lang/String;
Class Ljava/lang/Class;
Throwable Ljava/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: ActivityMainBindingoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)binding = ActivityMainBinding.inflate(layoutInflater)setContentView(binding.root)val util = Util()util.changeNameValue()  //修改stringutil.changeAgeValue()   //修改intutil.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) {//获取classjclass 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) {//获取classjclass 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) {//获取classjclass 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");//方式二:GetObjectClassjclass 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) {//获取jclassjclass 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) {//获取jclassjclass 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 classjclass 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: ActivityMainBindingoverride 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")}}
}

实战演练: 弹 Toast

c 代码

/*** 显示一个 Toast* Toast.makeText(this,"message",Toast.LENGTH_SHORT).show();*/
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_Util_showToast(JNIEnv *env, jclass clazz, jobject context,jstring message) {//获取Toastjclass cls = env->FindClass("android/widget/Toast");//获取 makeText 方法jmethodID makeText = env->GetStaticMethodID(cls, "makeText","(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;");//调用makeText方法, Toast.LENGTH_SHORT=0jobject toast = env->CallStaticObjectMethod(cls, makeText, context, message, 0);//获取 show 方法jmethodID show = env->GetMethodID(cls, "show", "()V");//调用 show 方法env->CallVoidMethod(toast, show);
}

java 方法声明


public class Util {native static void showToast(Context context, String message);
}

方法调用:

//显示一个toast
Util.showToast(this, "今天是周一")

实战演练:数组传值

Util.java

public class Util {native void run();//这个方法时c调用public void show(String[] array) {for (int i = 0; i < array.length; i++) {Log.d("show-", "" + i + "  " + array[i]);}}
}

可以看到 Util 有两个方法,一个是 run , 一个是 show 方法,参数是一个 String 数组。

我们现在来做,java 调用 run , 然后 c 实现的 run 再调用 show方法,并且传值 。

c 代码如下:

extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_Util_run(JNIEnv *env, jobject thiz) {jclass cls = env->GetObjectClass(thiz);//获取show反复jmethodID show = env->GetMethodID(cls, "show", "([Ljava/lang/String;)V");//定义string数组int size = 3;jclass strClass = env->FindClass("java/lang/String");jobjectArray resultArray = env->NewObjectArray(size, strClass, nullptr);//string数组赋值jstring strItem;for (int i = 0; i < size; ++i) {strItem = env->NewStringUTF("string in native");env->SetObjectArrayElement(resultArray, i, strItem);}//调用 show 方法env->CallVoidMethod(thiz, show, resultArray);
}

java 调用 run , 代码如下:

 Util().run()

输出结果如下:

D/show-: 0  string in native
D/show-: 1  string in native
D/show-: 2  string in native

Android NDK学习笔记3:JNI访问Java属性、方法相关推荐

  1. NDK学习笔记:JNI调用Java层方法创建Native的AudioTrack播放PCM(方法签名,CallXXXMethod)

    NDK学习笔记:JNI调用Java层方法创建Native的AudioTrack播放PCM 题目有点复杂,不过确实就是那么回事.这章想记录的内容比较多,先列出来: native static 与 nat ...

  2. Android NDK学习笔记4:JNI访问Java构造函数

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/119348263 本文出自[赵彦军的博客] 文章目录 方式一:NewObject 方 ...

  3. Android NDK学习笔记1:基础

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/119005718 本文出自[赵彦军的博客] 文章目录 (一)什么是Android N ...

  4. Android NDK学习笔记(转)

    前言 Android系统中的应用程序都是用Java开发的.Android NDK使我们能够在android上使用C/C++开发的原生代码.有两个理由使用NDK: 一是合理的重用现有的代码:二是在程序中 ...

  5. Android NDK学习笔记6:异常处理

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/119547007 本文出自[赵彦军的博客] 文章目录 JNI捕获异常 JNI抛出异常 ...

  6. Java学习笔记二十二:Java的方法重写

    Java的方法重写 一:什么是方法的重写: 如果子类对继承父类的方法不满意,是可以重写父类继承的方法的,当调用方法时会优先调用子类的方法. 语法规则 返回值类型.方法名.参数类型及个数都要与父类继承的 ...

  7. Android NDK学习笔记5:引用类型管理

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/119545225 本文出自[赵彦军的博客] 文章目录 局部引用 全局引用 弱引用 总 ...

  8. Android NDK学习笔记2:数组

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/119152933 本文出自[赵彦军的博客] 文章目录 java数组和jni数组对应关 ...

  9. java/android 设计模式学习笔记(3)---工厂方法模式

    这篇来介绍一下工厂方法模式(Factory Method Pattern),在实际开发过程中我们都习惯于直接使用 new 关键字用来创建一个对象,可是有时候对象的创造需要一系列的步骤:你可能需要计算或 ...

最新文章

  1. php asort,PHP asort():对数组排序(升序),并保持索引关系
  2. 【ACM】杭电OJ 1877 又一版A+B(进制转换)
  3. BK资本管理公司创始人阐述BCH接下来的三种“催化剂”
  4. 圆头像 微信小程序 绘图_小程序canvas绘制圆形微信头像
  5. 原创:QQ群发言统计
  6. 1977标准_超过8分,就是痛风!附痛风诊断新标准和治疗原则
  7. python顺序结构有一个入口_高楼万丈平地起,基础要打牢!Python获取类的层次结构和继承顺序...
  8. Bug访问豆瓣403forbidden
  9. AjaxPost、冒泡示例
  10. 将SSM架构中原来关于springSecurity3.x版本的写法配迁移到SpringBoot2.0框架中出现的问题解决记...
  11. 由任意二叉树的前序遍历序列和中序遍历序列求二叉树的思想方法_算法与数据结构基础 - 二叉树(Binary Tree)...
  12. python链表结构_CodeSalt | Python数据结构的实现 — 链表
  13. 使用VBA,优化处理Excel表格
  14. 服务器不能用pe安装win7系统安装,WinPE无法安装win7系统的完美解决方案
  15. c# 多线程 源码5
  16. DRAM知识整理系列(三):部分时序参数整理
  17. 第1章 Redis查阅官网和基本配置
  18. 三星手机大量死机!我反编译折腾半天后,发现竟然一个汉字引发的....
  19. ARFoundation入门1.0 什么是AR
  20. 附录002《 Git 中的重要概念》

热门文章

  1. 动态让控件超出屏幕_JAVA浏览器控件JxBrowser v7.5上线!更轻松处理Dynamic Favicons...
  2. c语言中获取用户控制台,【图片】【C语言】【控制台】提取腾讯通用户信息(id,用户名,手机)【erbi_lucifer吧】_百度贴吧...
  3. 惠普m180n故障码04_自动变速器挡位故障:挂前进挡或倒挡都不能行驶;不能升挡...
  4. della计算机驱动检测,nexus6安装BPTOOLS中的diag驱动图文教程
  5. 直播 | ACL 2021论文解读:表征与结构兼备,结构化语言模型R2D2
  6. AAAI 2020 开源论文 | 用于深度立体匹配的自适应单峰匹配代价体滤波
  7. KDD 18 论文解读 | GraphWave:一种全新的无监督网络嵌入方法
  8. 岗位推荐 | 阿里巴巴达摩院招聘自然语言处理、机器翻译算法专家
  9. 如何在Python中删除字符串中的所有反斜杠?
  10. 江苏python工资一般多少_会计行业一般工资多少?