(三)JNI常用示例
针对我之前文章的练习:JNI方法总结
1. 字符串
JAVA层:
- test.testString("HELLOWORLD");
JNI层:
- JNIEXPORT jstring JNICALL Java_com_aplex_canopen_CANopen_testString(JNIEnv *env, jobject obj, jstring str){
- jboolean isCopy;
- const char *cstr = env->GetStringUTFChars(str, &isCopy); //这个是把android默认的Unicode编码转换为UTF-8编码,然后得到数据
- if(isCopy==JNI_FALSE){
- LOGD("错误");
- } else if(isCopy==JNI_TRUE){
- LOGD("正确");
- }
- LOGD("UTF-8数据为:%s", cstr);
- LOGD("UTF-8数据长度为:%d", env->GetStringUTFLength(str));
- LOGD("Unicode数据长度为:%d", env->GetStringLength(str));
- env->ReleaseStringUTFChars(str, cstr);
- std::string strin = "hello world";
- return env->NewStringUTF(strin.c_str()); //生成一个新的UTF-8格式字符串
- }
结果:
- D/Canopencommand: 正确
- D/Canopencommand: UTF-8数据为:HELLOWORLD
- D/Canopencommand: UTF-8数据长度为:
- D/Canopencommand: Unicode数据长度为:
2. 基本类型数组
java层:
- test.testArray(new int[]{,,,,,,,,});
JNI层:
- JNIEXPORT void JNICALL Java_com_aplex_canopen_CANopen_testArray
- (JNIEnv *env, jobject obj, jintArray arr){
- jboolean isCopy;
- LOGD("######基本类型数组测试#########");
- //1. 拿到数组长度
- jint len = env->GetArrayLength(arr);
- LOGD("数组长度为:%d",len);
- //2. 拿到数组方法一:也就是转成可用的int*
- jint* val = env->GetIntArrayElements(arr, &isCopy);
- if(isCopy){
- LOGD("数组元素为");
- for (int i = ; i < len; ++i) {
- LOGD("元素%d:%d",i,val[i]);
- }
- }
- //3. 拿到数组方法二:拿指定长度数组
- jint val1[len];
- env->GetIntArrayRegion(arr, , len, val1); //0:起始索引; len: 长度; buf:需要放入的地方
- LOGD("数组元素1为");
- for (int i = ; i < len; ++i) {
- LOGD("元素%d:%d",i,val1[i]);
- }
- }
结果
- D/Canopencommand: ######基本类型数组测试#########
- D/Canopencommand: 数组长度为:
- D/Canopencommand: 数组元素为
- D/Canopencommand: 元素0:
- D/Canopencommand: 元素1:
- D/Canopencommand: 元素2:
- D/Canopencommand: 元素3:
- D/Canopencommand: 元素4:
- D/Canopencommand: 元素5:
- D/Canopencommand: 元素6:
- D/Canopencommand: 元素7:
- D/Canopencommand: 元素8:
- D/Canopencommand: 数组元素1为
- D/Canopencommand: 元素0:
- D/Canopencommand: 元素1:
- D/Canopencommand: 元素2:
- D/Canopencommand: 元素3:
- D/Canopencommand: 元素4:
- D/Canopencommand: 元素5:
- D/Canopencommand: 元素6:
- D/Canopencommand: 元素7:
- D/Canopencommand: 元素8:
3. 对象类型数组
JAVA层:
- test.testArrayObject(new String[]{"haha","hehe","wawa","dada"});
JNI层:
- JNIEXPORT void JNICALL Java_com_aplex_canopen_CANopen_testArrayObject
- (JNIEnv *env, jobject obj, jobjectArray strArr){
- jboolean isCopy;
- LOGD("######对象类型数组测试#########");
- int len = env->GetArrayLength(strArr); //拿到数组长度
- //1. 拿到对象数组数据
- for (int i = ; i < len; ++i) {
- jstring str = (jstring)env->GetObjectArrayElement(strArr, i); //拿到对象数组的元素:注意要强制转换
- const char *cstr = env->GetStringUTFChars(str, &isCopy);
- LOGD("字符串%d为:%s",i,cstr);
- env->ReleaseStringUTFChars(str, cstr);
- }
- //2. 设置对象数组数据
- jstring str = env->NewStringUTF("abcdefg");
- env->SetObjectArrayElement(strArr, , str); //修改对象数组中的数据
- LOGD("修改后再看一遍2");
- for (int i = ; i < len; ++i) {
- jstring str = (jstring)env->GetObjectArrayElement(strArr, i);
- const char *cstr = env->GetStringUTFChars(str, &isCopy);
- LOGD("字符串%d为:%s",i,cstr);
- env->ReleaseStringUTFChars(str, cstr);
- }
- //3. 构造一个新的对象数组
- jclass strClass = env->FindClass("java/lang/String");
- jobjectArray newStr = env->NewObjectArray(len-, strClass, ); //创建一个新的对象数组
- len = env->GetArrayLength(newStr); //拿到新创立数组的长度
- for (int i = ; i < len; ++i) {
- jstring str = (jstring)env->GetObjectArrayElement(strArr, i); //拿到对象数组的元素:注意要强制转换
- env->SetObjectArrayElement(newStr, i, str); //修改对象数组中的数据
- }
- LOGD("修改后再看一遍3");
- for (int i = ; i < len; ++i) {
- jstring str = (jstring)env->GetObjectArrayElement(newStr, i);
- const char *cstr = env->GetStringUTFChars(str, &isCopy);
- LOGD("字符串%d为:%s",i,cstr);
- env->ReleaseStringUTFChars(str, cstr);
- }
- }
结果:
- ######对象类型数组测试#########
- D/Canopencommand: 字符串0为:haha
- D/Canopencommand: 字符串1为:hehe
- D/Canopencommand: 字符串2为:wawa
- D/Canopencommand: 字符串3为:dada
- D/Canopencommand: 修改后再看一遍2
- D/Canopencommand: 字符串0为:abcdefg
- D/Canopencommand: 字符串1为:hehe
- D/Canopencommand: 字符串2为:wawa
- D/Canopencommand: 字符串3为:dada
- D/Canopencommand: 修改后再看一遍3
- D/Canopencommand: 字符串0为:abcdefg
- D/Canopencommand: 字符串1为:hehe
- D/Canopencommand: 字符串2为:wawa
4. 在JNI中调用实例化对象中的方法1:(使用自身对象,自身已被实例化)
JAVA层:测试对象
- public class CANopen {
- private static final String TAG = "CANopen";
- static {
- Log.d(TAG, "static1");
- System.loadLibrary("Canopen-lib");
- Log.d(TAG, "static2");
- }
- public native void testCallMethod();
- private void JNIcallback(){
- Log.d(TAG, "这是JNI从C/C++回调JAVA实例化对象中的方法");
- }
- private int JNIcallback2(int a, byte b){
- Log.d(TAG, "整型="+a+";字节="+b);
- return ;
- }
- private String JNIcallback3(int a, String b, byte[]c){
- Log.d(TAG, "整型="+a);
- Log.d(TAG,"字符串="+b);
- Log.d(TAG,"数组长度="+c.length);
- return new String("hello world");
- }
- }
JAVA层:
- Log.d(TAG, "onCreate1");
- caNopen.testCallMethod();
- Log.d(TAG, "onCreate2");
JNI层:
- JNIEXPORT void JNICALL Java_com_aplex_canopen_CANopen_testCallMethod
- (JNIEnv *env, jobject obj){
- jboolean isCopy;
- //1. 先调用一个比较简单的(无参无返回)
- LOGD("##########第一个############");
- jclass jc = env->GetObjectClass(obj); //通过实例化对象找到类
- jmethodID id = env->GetMethodID(jc, "JNIcallback", "()V"); //找到实例化对象里函数的ID
- env->CallVoidMethod(obj, id); //调用obj这个实例化对象里的函数id
- //2. 调用稍微复杂点的(基本类型参数和返回值)
- LOGD("##########第二个############");
- jclass jc2 = env->GetObjectClass(obj); //通过实例化对象找到类
- jmethodID id2 = env->GetMethodID(jc2, "JNIcallback2", "(IB)I"); //找到实例化对象里函数的ID
- jint i = env->CallIntMethod(obj, id2, 0x1234, ); //调用obj这个实例化对象里的函数id
- LOGD("JNI中返回参数=%d",i);
- //3. 调用一个比较复杂的(带对象类型参数和返回值)
- LOGD("##########第三个############");
- jclass jc3 = env->GetObjectClass(obj); //通过实例化对象找到类
- jmethodID id3 = env->GetMethodID(jc3, "JNIcallback3", "(ILjava/lang/String;[B)Ljava/lang/String;"); //找到实例化对象里函数的ID
- //创建byte数组,注意:无法赋值!!!
- jbyteArray byteArray = env->NewByteArray();
- int len = env->GetArrayLength(byteArray);
- //创建一个string并赋值
- jstring jstr = env->NewStringUTF("fuck!!");
- jstring str = (jstring)env->CallObjectMethod(obj, id3, , jstr,byteArray); //调用obj2这个实例化对象里的函数id,返回值是对象,要进行强制转换
- const char* cstr = env->GetStringUTFChars(str,&isCopy);
- LOGD("JNI中打印:%s", cstr);
- env->ReleaseStringUTFChars(str, cstr);
- }
结果:
- D/MainActivity: onCreate1
- D/Canopencommand: ##########第一个############
- D/CANopen: 这是JNI从C/C++回调JAVA实例化对象中的方法
- D/Canopencommand: ##########第二个############
- D/CANopen: 整型=;字节=
- D/Canopencommand: JNI中返回参数=
- D/Canopencommand: ##########第三个############
- D/CANopen: 整型=
- D/CANopen: 字符串=fuck!!
- D/CANopen: 数组长度=
- D/Canopencommand: JNI中打印:hello world
- D/MainActivity: onCreate2
5. 在JNI中调用实例化对象中的方法2:(新建实例化对象,修改对象的属性值,调用对象方法)
需要实例化的对象:
- package com.aplex.canopen;
- import android.util.Log;
- public class TestClass {
- private String TAG = "TestClass";
- private int a;
- TestClass(){
- a = ;
- Log.d(TAG,"调用无参构造函数");
- }
- TestClass(int a){
- this.a = a;
- Log.d(TAG,"调用有参构造函数="+a);
- }
- public int getValue(){
- Log.d(TAG, "a="+this.a);
- return this.a;
- }
- }
JAVA层:
- Log.d(TAG, "onCreate1");
- caNopen.testCallMethod2();
- Log.d(TAG, "onCreate2");
JNI层:
- JNIEXPORT void JNICALL Java_com_aplex_canopen_CANopen_testCallMethod2
- (JNIEnv *env, jobject obj){
- //1. 调用无参构造函数、修改变量(属性)值
- LOGD("##########调用无参构造函数############");
- jclass jc = env->FindClass("com/aplex/canopen/TestClass"); //找到类,该类未被实例化
- jmethodID initID = env->GetMethodID(jc, "<init>", "()V");//找到构造函数的id;注意:构造函数"<init>"为固定值
- jobject mobj = env->NewObject(jc, initID); //实例化一个对象
- jmethodID funcID = env->GetMethodID(jc, "getValue", "()I"); //拿到方法的ID
- jint i = env->CallIntMethod(mobj, funcID); //调用方法
- LOGD("修改前查看函数返回的a=%d",i);
- jfieldID fieldID = env->GetFieldID(jc, "a", "I"); //拿到变量(属性)的ID
- jint ii = env->GetIntField(mobj, fieldID);
- LOGD("查看拿到的值a=%d",ii);
- ii = ;
- env->SetIntField(mobj, fieldID, ii);
- jint iii = env->CallIntMethod(mobj, funcID); //再次调用查看是否修改属性值
- LOGD("修改后查看函数返回的a=%d",iii);
- //2. 调用有参构造函数
- LOGD("##########调用有参构造函数############");
- jclass jc2 = env->FindClass("com/aplex/canopen/TestClass");
- jmethodID initID2 = env->GetMethodID(jc2, "<init>", "(I)V"); //注意这里:"(I)V"
- jobject mobj2 = env->NewObject(jc2, initID2, );
- jmethodID funcID2 = env->GetMethodID(jc2, "getValue", "()I");
- jint i2 = env->CallIntMethod(mobj2, funcID2);
- LOGD("a=%d",i2);
- }
结果:
- D/MainActivity: onCreate1
- D/Canopencommand: ##########调用无参构造函数############
- D/TestClass: 调用无参构造函数
- D/TestClass: a=
- D/Canopencommand: 修改前查看函数返回的a=
- D/Canopencommand: 查看拿到的值a=
- D/TestClass: a=
- D/Canopencommand: 修改后查看函数返回的a=
- D/Canopencommand: ##########调用有参构造函数############
- D/TestClass: 调用有参构造函数=
- D/TestClass: a=
- D/Canopencommand: a=
- D/MainActivity: onCreate2
6. 异常处理
JAVA层:
- caNopen.testException();
JNI层:
- JNIEXPORT void JNICALL Java_com_aplex_canopen_CANopen_testException
- (JNIEnv *env, jobject obj){
- jclass jc = env->FindClass("java/io/IOException");
- env->ThrowNew(jc, "异常测试");
- }
结果:
- E/AndroidRuntime: FATAL EXCEPTION: main
- Process: com.aplex.canopen, PID:
- java.lang.RuntimeException: Unable to start activity ComponentInfo{com.aplex.canopen/com.aplex.canopen.MainActivity}: java.io.IOException: 异常测试
- at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:)
- at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:)
- at android.app.ActivityThread.-wrap11(ActivityThread.java)
- at android.app.ActivityThread$H.handleMessage(ActivityThread.java:)
- at android.os.Handler.dispatchMessage(Handler.java:)
- at android.os.Looper.loop(Looper.java:)
- at android.app.ActivityThread.main(ActivityThread.java:)
- at java.lang.reflect.Method.invoke(Native Method)
- at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:)
- at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:)
- Caused by: java.io.IOException: 异常测试
- at com.aplex.canopen.CANopen.testException(Native Method)
- at com.aplex.canopen.MainActivity.onCreate(MainActivity.java:)
- at android.app.Activity.performCreate(Activity.java:)
- at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:)
- at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:)
- at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:)
- at android.app.ActivityThread.-wrap11(ActivityThread.java)
- at android.app.ActivityThread$H.handleMessage(ActivityThread.java:)
- at android.os.Handler.dispatchMessage(Handler.java:)
- at android.os.Looper.loop(Looper.java:)
- at android.app.ActivityThread.main(ActivityThread.java:)
- at java.lang.reflect.Method.invoke(Native Method)
- at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:)
- at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:)
(三)JNI常用示例的更多相关文章
- php实现的三个常用加密解密功能函数示例
目录 算法一: 算法二: 算法三(改进第一个加密之后的算法) 本文实例讲述了php实现的三个常用加密解密功能函数.分享给大家供大家参考,具体如下: 算法一: //加密函数 function lock_ ...
- 减少可执行程序size的三个常用软件
减少可执行程序size的三个常用软件 linux下面,直接用strip 这个命令 #:strip xxx 可以去掉编译调试信息和各种符号表,能够大大减小可执行程序size windows下面这种exe ...
- java注解学习(1)注解的作用和三个常用java内置注解
今天,记录一下自己学习的关于注解方面的知识. Annotation是从JDK5.0开始引入的新技术 Annotation的作用: -不是程序本身,可以对程序做出解释(这一点和注释没什么区别) -可以被 ...
- js之checkbox判断常用示例
checkbox常用示例可参考: 关于checkbox自动选中 checkbox选中并通过ajax传数组到后台接收 MP实战系列(十三)之批量修改操作(前后台异步交互) 本次说的是,还是关于智能门锁开 ...
- JavaScrip——初学(三个常用对话框及方法调用)
一. 三个常用对话框: 1.都必须写在<scrip></scrip> <body> <font>alert("报错")</fo ...
- go的三个常用命令go run go build go install
go的三个常用命令 go run go build go install 命令源码文件:含有 main函数 的文件 库源码文件:不包含 main函数 的文件, 主要用于编译成静态文件.a供其他包调用 ...
- Linux curl 常用示例
本篇文章包含了curl的常用案例使用. 如果想了解curl选项的详细说明,请参考前一篇文章「Linux curl 命令详解」. 常见网页访问示例 基本用法 访问一个网页 curl https://ww ...
- (三) Docker 常用操作与CentOS7 防火墙命令
参考并感谢 Docker 常用命令 https://docs.docker.com/engine/reference/commandline/docker/ Docker 登录docker账户 doc ...
- Linux ar命令介绍 和常用示例
制作静态库要用到ar命令,命令格式: ar [-]{dmpqrtx}[abcfilNoPsSuvV] [membername] [count] archive files... {dmpqrtx}中的 ...
随机推荐
- C++(指针和高级指针)-上篇
[在指针中存储地址] int *pAge=nullptr; //将PAge声明为int指针,即用于存储int变量的地址 如果将指针初始化为0或者NUll,以后必须将变量的地址赋给它,如下例代码: ; ...
- 开源一款强大的文件服务组件(QJ_FileCenter)(系列二 安装说明)
系列文章 1. 开源一款强大的文件服务组件(QJ_FileCenter)(系列一) 2. 开源一款强大的文件服务组件(QJ_FileCenter)(系列二 安装说明) 3. 开源一款强大的文件服务组件 ...
- Android Library 使用规则
1. 一个项目必须声明为 is library.使用该 library 的项目导入该 library. 2. library 的 manifect 中 activity 的声明需明确包名以避免找不到. ...
- 索引+sql优化
索引的概念: 索引是提高查询速度的一种手段.索引有很多种,以下是索引树的结构 要求查询出薪资大于5000的雇员信息,只要在树中找到5000的节点,直接查询该节点右边的数据即可,左边就不用管了,这样提高 ...
- Python3.5 学习四
装饰器 定义:本质是函数,装饰其他函数,即为其他函数添加附加功能的 原则: 1 不能修改被装饰函数的源代码 2 不能改变被装饰函数的调用方式(对于被装饰函数来说完全透明,不会受影响) 实现装饰器功能的 ...
- 【文文殿下】后缀自动机(Suffix Automaton,SAM)学习笔记
前言 后缀自动机是一个强大的数据结构,能够解决很多字符串相关的(String-related)问题. 例如:他可以查询一个字符串在另一个字符串中出现的所有子串,以及查询一个字符串中本质不同的字符串的个 ...
- Python数据分析之文本处理词频统计
1.项目背景: 原本计划着爬某房产网站的数据做点分析, 结果数据太烂了,链家网的数据干净点, 但都是新开楼盘,没有时间维度,分析意义不大. 学习的步伐不能ting,自然语言处理还的go on 2.分析 ...
- SpringData JPA实现CRUD,分页与多参数排序
Spring Data 项目的目的是为了简化构建基于 Spring 框架应用的数据访问计数,包括非关系数据库.Map-Reduce 框架.云数据服务等等,SpringData JPA是简化创建 JPA ...
- 给对象和函数添加method方法
蝴蝶书中有一个method方法,用来给函数定义方法.看了之后,想着能不能给对象也定义方法呢?. 下面的代码可以实现给函数定义方法: //Function method Function.prototy ...
- 10分钟教你用Python打造天气机器人+关键字自动回复+定时发送
01 前言 Hello,各位小伙伴.自上次我们介绍了Python实现天气预报的功能以后,那个小程序还有诸多不完善的地方,今天,我们再次来完善一下我们的小程序.比如我们想给机器人发“天气”等关键字,它就 ...