针对我之前文章的练习: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. .NET Framework 历史版本(2017年)

    .NET简介 这个平台相信我们都知道,不过随着技术发展,现在的.NET平台也今非昔比. .NET平台类似Java平台,是微软于2000年推出的Windows操作系统的应用软件开发框架,发展至今形成巨大 ...

  2. 关于EF的一点小记录

    今日新闻:朝鲜要改革开放了!!!比你牛逼的人都在努力,你还有理由懒惰吗? 宇宙强大IDE配套的EF问题记录 今天做数据添加时,Id我设置为int类型了,结果在做Add操作时报的错让我摸不着头脑,后来问 ...

  3. winform app.cpnfig 文件的引用

    1.app.config配置文件修改 <?xml version="1.0" encoding="utf-8"?> <configuratio ...

  4. ANE-如何加入ane,调试时又不报错

    有时候我们加入ane,即使没有调用ane的功能,debug的时候也会报错无法调试,这是为什么呢?因为我们的ane没有把default包含进去. 首先我们的extension.xml要把default节 ...

  5. git删除未监视的文件

    新增的文件使用git status查看会提示Untracked files,如果想要删除Untracked files,可以使用如下命令: git clean -f # 删除Untracked fil ...

  6. C# 键盘中的按键对应KeyValue

    首先先看一下什麼情況下需要對按鍵進行識別: KeyPress事件響應函數中,有KeyPressEventArgs, 對應於e.KeyChar; KeyDown事件響應中有KeyEventArgs 求取 ...

  7. Using RDP to connect Windows remote desktop with Linux

    安装rdesktop(一般情况下不需要这么做): sudo apt-get install rdesktop 执行连接: rdesktop xxx.xxx.xxx.xxx:3389 -u admini ...

  8. IDEA 引入外部jar包 pom 配置,防止打包失败

    1. <!--添加外部依赖-->        <dependency>            <groupId>Ice</groupId>       ...

  9. Laravel 完整开源项目大全

    来自 Laravel学院:http://laravelacademy.org/ http://laravelacademy.org/laravel-project 原型项目 Laravel 5 Boi ...

  10. 浅谈Android选项卡(四)

    前面几篇介绍的选项的用法,基本上使用TabActivity.ViewPager.已经基本上满足开发需求了.但是这里再介绍一种小技巧,在有的时候,感觉使用前面的ViewPager和Fragment时候, ...