针对我之前文章的练习: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. 推荐两款国人开发的html前段框架

    1.http://www.h-ui.net/  H-ui前端框架官方网站 2.http://www.builive.com/  BUI是基于JQuery的富客户端UI框架

  2. SQL 从数据库中随机取n条数据

    用NEWID()方法. * ,NEWID() AS random from [toblename] order by random 其中的1可以换成其他任意整数,表示取的数据条数

  3. ASP.NET RouteModule相关的一些东西

    Asp.NET中的路由配置,首先要提到的几个相关类型,Route ,RouteBase,RouteData,RouteTable,RouteCollection 这几个.下面我一次回忆一下,有需要的朋 ...

  4. c# 利用t4模板,自动生成Model类

    我们在用ORM(比如dapper)的时候,很多时候都需要自己写Model层(当然也有很多orm框架自带了这种功能,比如ef),特别是表里字段比较多的时候,一个Model要写半天,而且Model如果用于 ...

  5. Mycat SqlServer Do not have slave connection to use, use master connection instead

    Do not have slave connection to use, use master connection instead 很奇怪啊 都是按照配置配置的 怎么就是不通呢 有点怀疑人生了吧 其 ...

  6. ES6学习之const声明常量的学习

    在ES中const关键字用来声明常量,const声明的一经定义不能修改 和let特性差不多, ; console.log(a); a = ; //报错 const定义完常量后必须赋值,后面不允许再次赋 ...

  7. java学习笔记—web计算器(36)

    MVC模式 模式主要的任务是帮助开发者解决一类问题. MVC模式主要是用于规划你的网站的开发的一个基本的结构. Servlet记住充当的是控制器层.cn.itcast.controller Java类 ...

  8. c++实验5 顺序/链式队列

    链式队列及循环队列 1.循环队列的实现(请采用模板类及模板函数实现) [实现提示] 同时可参见教材p65-p67页的ADT描述及算法实现及ppt)函数.类名称等可自定义,部分变量请加上学号后3位.也可 ...

  9. 操作mysql的指令

    1,通过ip,端口,用户名,密码登陆数据 命令格式为:mysql -h ip -u root -p -P 3306例如:mysql -h 127.0.0.1 -u root -p -P 3306 2, ...

  10. elasticsearch5.2.1使用logstash同步mysql

    centos 本人亲测可以  首先安装好mysql,elasticsearch   不懂的请参考另一篇文章 安装logstash官方:https://www.elastic.co/guide/en/l ...