Android NDK学习笔记3:JNI访问Java属性、方法
转载请标明出处: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属性、方法相关推荐
- NDK学习笔记:JNI调用Java层方法创建Native的AudioTrack播放PCM(方法签名,CallXXXMethod)
NDK学习笔记:JNI调用Java层方法创建Native的AudioTrack播放PCM 题目有点复杂,不过确实就是那么回事.这章想记录的内容比较多,先列出来: native static 与 nat ...
- Android NDK学习笔记4:JNI访问Java构造函数
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/119348263 本文出自[赵彦军的博客] 文章目录 方式一:NewObject 方 ...
- Android NDK学习笔记1:基础
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/119005718 本文出自[赵彦军的博客] 文章目录 (一)什么是Android N ...
- Android NDK学习笔记(转)
前言 Android系统中的应用程序都是用Java开发的.Android NDK使我们能够在android上使用C/C++开发的原生代码.有两个理由使用NDK: 一是合理的重用现有的代码:二是在程序中 ...
- Android NDK学习笔记6:异常处理
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/119547007 本文出自[赵彦军的博客] 文章目录 JNI捕获异常 JNI抛出异常 ...
- Java学习笔记二十二:Java的方法重写
Java的方法重写 一:什么是方法的重写: 如果子类对继承父类的方法不满意,是可以重写父类继承的方法的,当调用方法时会优先调用子类的方法. 语法规则 返回值类型.方法名.参数类型及个数都要与父类继承的 ...
- Android NDK学习笔记5:引用类型管理
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/119545225 本文出自[赵彦军的博客] 文章目录 局部引用 全局引用 弱引用 总 ...
- Android NDK学习笔记2:数组
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/119152933 本文出自[赵彦军的博客] 文章目录 java数组和jni数组对应关 ...
- java/android 设计模式学习笔记(3)---工厂方法模式
这篇来介绍一下工厂方法模式(Factory Method Pattern),在实际开发过程中我们都习惯于直接使用 new 关键字用来创建一个对象,可是有时候对象的创造需要一系列的步骤:你可能需要计算或 ...
最新文章
- php asort,PHP asort():对数组排序(升序),并保持索引关系
- 【ACM】杭电OJ 1877 又一版A+B(进制转换)
- BK资本管理公司创始人阐述BCH接下来的三种“催化剂”
- 圆头像 微信小程序 绘图_小程序canvas绘制圆形微信头像
- 原创:QQ群发言统计
- 1977标准_超过8分,就是痛风!附痛风诊断新标准和治疗原则
- python顺序结构有一个入口_高楼万丈平地起,基础要打牢!Python获取类的层次结构和继承顺序...
- Bug访问豆瓣403forbidden
- AjaxPost、冒泡示例
- 将SSM架构中原来关于springSecurity3.x版本的写法配迁移到SpringBoot2.0框架中出现的问题解决记...
- 由任意二叉树的前序遍历序列和中序遍历序列求二叉树的思想方法_算法与数据结构基础 - 二叉树(Binary Tree)...
- python链表结构_CodeSalt | Python数据结构的实现 — 链表
- 使用VBA,优化处理Excel表格
- 服务器不能用pe安装win7系统安装,WinPE无法安装win7系统的完美解决方案
- c# 多线程 源码5
- DRAM知识整理系列(三):部分时序参数整理
- 第1章 Redis查阅官网和基本配置
- 三星手机大量死机!我反编译折腾半天后,发现竟然一个汉字引发的....
- ARFoundation入门1.0 什么是AR
- 附录002《 Git 中的重要概念》
热门文章
- 动态让控件超出屏幕_JAVA浏览器控件JxBrowser v7.5上线!更轻松处理Dynamic Favicons...
- c语言中获取用户控制台,【图片】【C语言】【控制台】提取腾讯通用户信息(id,用户名,手机)【erbi_lucifer吧】_百度贴吧...
- 惠普m180n故障码04_自动变速器挡位故障:挂前进挡或倒挡都不能行驶;不能升挡...
- della计算机驱动检测,nexus6安装BPTOOLS中的diag驱动图文教程
- 直播 | ACL 2021论文解读:表征与结构兼备,结构化语言模型R2D2
- AAAI 2020 开源论文 | 用于深度立体匹配的自适应单峰匹配代价体滤波
- KDD 18 论文解读 | GraphWave:一种全新的无监督网络嵌入方法
- 岗位推荐 | 阿里巴巴达摩院招聘自然语言处理、机器翻译算法专家
- 如何在Python中删除字符串中的所有反斜杠?
- 江苏python工资一般多少_会计行业一般工资多少?