针对我之前文章的练习: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常用示例的更多相关文章

  1. php实现的三个常用加密解密功能函数示例

    目录 算法一: 算法二: 算法三(改进第一个加密之后的算法) 本文实例讲述了php实现的三个常用加密解密功能函数.分享给大家供大家参考,具体如下: 算法一: //加密函数 function lock_ ...

  2. 减少可执行程序size的三个常用软件

    减少可执行程序size的三个常用软件 linux下面,直接用strip 这个命令 #:strip xxx 可以去掉编译调试信息和各种符号表,能够大大减小可执行程序size windows下面这种exe ...

  3. java注解学习(1)注解的作用和三个常用java内置注解

    今天,记录一下自己学习的关于注解方面的知识. Annotation是从JDK5.0开始引入的新技术 Annotation的作用: -不是程序本身,可以对程序做出解释(这一点和注释没什么区别) -可以被 ...

  4. js之checkbox判断常用示例

    checkbox常用示例可参考: 关于checkbox自动选中 checkbox选中并通过ajax传数组到后台接收 MP实战系列(十三)之批量修改操作(前后台异步交互) 本次说的是,还是关于智能门锁开 ...

  5. JavaScrip——初学(三个常用对话框及方法调用)

    一. 三个常用对话框: 1.都必须写在<scrip></scrip> <body> <font>alert("报错")</fo ...

  6. go的三个常用命令go run go build go install

    go的三个常用命令 go run go build go install 命令源码文件:含有 main函数 的文件 库源码文件:不包含 main函数 的文件, 主要用于编译成静态文件.a供其他包调用 ...

  7. Linux curl 常用示例

    本篇文章包含了curl的常用案例使用. 如果想了解curl选项的详细说明,请参考前一篇文章「Linux curl 命令详解」. 常见网页访问示例 基本用法 访问一个网页 curl https://ww ...

  8. (三) Docker 常用操作与CentOS7 防火墙命令

    参考并感谢 Docker 常用命令 https://docs.docker.com/engine/reference/commandline/docker/ Docker 登录docker账户 doc ...

  9. Linux ar命令介绍 和常用示例

    制作静态库要用到ar命令,命令格式: ar [-]{dmpqrtx}[abcfilNoPsSuvV] [membername] [count] archive files... {dmpqrtx}中的 ...

随机推荐

  1. 微信浏览器禁止app下载链接的两种处理方法

    最近替朋友放一个微信下载链接,通过二维码扫描下载. 通过扫描二维码下载APP已成为一个非常方便的方式,微信也成为扫描二维码重要的工具,但是扫描后微信浏览器会对APK和appStore的链接进行屏蔽,导 ...

  2. “全栈2019”Java异常第十三章:访问异常堆栈跟踪信息

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...

  3. “全栈2019”Java第八十九章:接口中能定义内部类吗?

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  4. AcDbTable表格实体的简单例子

    例子是创建一个含有表格实体的块定义 效果如下(手动插入的块) 源代码如下,简单示意,采用了我不是很熟悉的智能指针创建实体对象,代码仅供参考 AcDbObjectPointer<AcDbTable ...

  5. CentOS运行C++语言的Hello World

    1,编写代码,hello.cpp #include <iostream> using namespace std; int main(){ cout<<"hello ...

  6. 干货 | 精选《SQL注入、渗透、反病毒》学习总结集锦给你们~

    学到手的都是本事,如果觉得对你有帮助也欢迎分享给身边的基友们吧! 分享干货,手留余香哦~ 本次“开学季拜师活动”的徒弟们在师父的精心指导下,在短短5天内得到了迅速地成长,以前或当时遇到的问题都能够柳暗 ...

  7. JavaScript创建对象的4种方法

    我们有很多种方式去构造一个对象.可以构造一个对象字面量,也可以和new前缀连用去调用一个构造器函数,或者可以使用Object.create方法去构造一个已经存在的对象的新实例,还可以调用任意一个会返回 ...

  8. mybatis的执行流程

    1.SqlSessionFactoryBuilder与SqlSessionFactory 我们一般在使用mybatis是都会通过new SqlSessionFactoryBuilder.build(. ...

  9. Cocoa对象——根类

    [转载自:http://mobile.51cto.com/iphone-274229.htm] Cocoa对象 根类是本文要介绍的内容,仅凭Objective-C语言和运行环境并不足以构造哪怕是最简单 ...

  10. Maven 依赖管理问题小计

    刚学Maven,遇到点小问题,记录一下.https://maven.apache.org/ 问题的起因是项目中使用了 Hibernate Validator ,但是运行起来后总是不能按照设置的注解校验 ...