针对我之前文章的练习:JNI方法总结

1. 字符串

JAVA层:

  1. test.testString("HELLOWORLD");

JNI层:

  1. JNIEXPORT jstring JNICALL Java_com_aplex_canopen_CANopen_testString(JNIEnv *env, jobject obj, jstring str){
  2.  
  3. jboolean isCopy;
  4. const char *cstr = env->GetStringUTFChars(str, &isCopy); //这个是把android默认的Unicode编码转换为UTF-8编码,然后得到数据
  5.  
  6. if(isCopy==JNI_FALSE){
  7. LOGD("错误");
  8. } else if(isCopy==JNI_TRUE){
  9. LOGD("正确");
  10. }
  11. LOGD("UTF-8数据为:%s", cstr);
  12. LOGD("UTF-8数据长度为:%d", env->GetStringUTFLength(str));
  13. LOGD("Unicode数据长度为:%d", env->GetStringLength(str));
  14.  
  15. env->ReleaseStringUTFChars(str, cstr);
  16.  
  17. std::string strin = "hello world";
  18. return env->NewStringUTF(strin.c_str()); //生成一个新的UTF-8格式字符串
  19. }

结果:

  1. D/Canopencommand: 正确
  2. D/Canopencommand: UTF-8数据为:HELLOWORLD
  3. D/Canopencommand: UTF-8数据长度为:
  4. D/Canopencommand: Unicode数据长度为:

2. 基本类型数组

java层:

  1. test.testArray(new int[]{,,,,,,,,});

JNI层:

  1. JNIEXPORT void JNICALL Java_com_aplex_canopen_CANopen_testArray
  2. (JNIEnv *env, jobject obj, jintArray arr){
  3. jboolean isCopy;
  4. LOGD("######基本类型数组测试#########");
  5.  
  6. //1. 拿到数组长度
  7. jint len = env->GetArrayLength(arr);
  8. LOGD("数组长度为:%d",len);
  9.  
  10. //2. 拿到数组方法一:也就是转成可用的int*
  11. jint* val = env->GetIntArrayElements(arr, &isCopy);
  12. if(isCopy){
  13. LOGD("数组元素为");
  14. for (int i = ; i < len; ++i) {
  15. LOGD("元素%d:%d",i,val[i]);
  16. }
  17. }
  18.  
  19. //3. 拿到数组方法二:拿指定长度数组
  20. jint val1[len];
  21. env->GetIntArrayRegion(arr, , len, val1); //0:起始索引; len: 长度; buf:需要放入的地方
  22. LOGD("数组元素1为");
  23. for (int i = ; i < len; ++i) {
  24. LOGD("元素%d:%d",i,val1[i]);
  25. }
  26. }

结果

  1. D/Canopencommand: ######基本类型数组测试#########
  2. D/Canopencommand: 数组长度为:
  3. D/Canopencommand: 数组元素为
  4. D/Canopencommand: 元素0:
  5. D/Canopencommand: 元素1:
  6. D/Canopencommand: 元素2:
  7. D/Canopencommand: 元素3:
  8. D/Canopencommand: 元素4:
  9. D/Canopencommand: 元素5:
  10. D/Canopencommand: 元素6:
  11. D/Canopencommand: 元素7:
  12. D/Canopencommand: 元素8:
  13. D/Canopencommand: 数组元素1
  14. D/Canopencommand: 元素0:
  15. D/Canopencommand: 元素1:
  16. D/Canopencommand: 元素2:
  17. D/Canopencommand: 元素3:
  18. D/Canopencommand: 元素4:
  19. D/Canopencommand: 元素5:
  20. D/Canopencommand: 元素6:
  21. D/Canopencommand: 元素7:
  22. D/Canopencommand: 元素8:

3. 对象类型数组

JAVA层:

  1. test.testArrayObject(new String[]{"haha","hehe","wawa","dada"});

JNI层:

  1. JNIEXPORT void JNICALL Java_com_aplex_canopen_CANopen_testArrayObject
  2. (JNIEnv *env, jobject obj, jobjectArray strArr){
  3. jboolean isCopy;
  4. LOGD("######对象类型数组测试#########");
  5.  
  6. int len = env->GetArrayLength(strArr); //拿到数组长度
  7.  
  8. //1. 拿到对象数组数据
  9. for (int i = ; i < len; ++i) {
  10. jstring str = (jstring)env->GetObjectArrayElement(strArr, i); //拿到对象数组的元素:注意要强制转换
  11. const char *cstr = env->GetStringUTFChars(str, &isCopy);
  12. LOGD("字符串%d为:%s",i,cstr);
  13. env->ReleaseStringUTFChars(str, cstr);
  14. }
  15.  
  16. //2. 设置对象数组数据
  17. jstring str = env->NewStringUTF("abcdefg");
  18. env->SetObjectArrayElement(strArr, , str); //修改对象数组中的数据
  19. LOGD("修改后再看一遍2");
  20. for (int i = ; i < len; ++i) {
  21. jstring str = (jstring)env->GetObjectArrayElement(strArr, i);
  22. const char *cstr = env->GetStringUTFChars(str, &isCopy);
  23. LOGD("字符串%d为:%s",i,cstr);
  24. env->ReleaseStringUTFChars(str, cstr);
  25. }
  26.  
  27. //3. 构造一个新的对象数组
  28. jclass strClass = env->FindClass("java/lang/String");
  29. jobjectArray newStr = env->NewObjectArray(len-, strClass, ); //创建一个新的对象数组
  30. len = env->GetArrayLength(newStr); //拿到新创立数组的长度
  31. for (int i = ; i < len; ++i) {
  32. jstring str = (jstring)env->GetObjectArrayElement(strArr, i); //拿到对象数组的元素:注意要强制转换
  33. env->SetObjectArrayElement(newStr, i, str); //修改对象数组中的数据
  34. }
  35. LOGD("修改后再看一遍3");
  36. for (int i = ; i < len; ++i) {
  37. jstring str = (jstring)env->GetObjectArrayElement(newStr, i);
  38. const char *cstr = env->GetStringUTFChars(str, &isCopy);
  39. LOGD("字符串%d为:%s",i,cstr);
  40. env->ReleaseStringUTFChars(str, cstr);
  41. }
  42.  
  43. }

结果:

  1. ######对象类型数组测试#########
  2. D/Canopencommand: 字符串0为:haha
  3. D/Canopencommand: 字符串1为:hehe
  4. D/Canopencommand: 字符串2为:wawa
  5. D/Canopencommand: 字符串3为:dada
  6. D/Canopencommand: 修改后再看一遍2
  7. D/Canopencommand: 字符串0为:abcdefg
  8. D/Canopencommand: 字符串1为:hehe
  9. D/Canopencommand: 字符串2为:wawa
  10. D/Canopencommand: 字符串3为:dada
  11. D/Canopencommand: 修改后再看一遍3
  12. D/Canopencommand: 字符串0为:abcdefg
  13. D/Canopencommand: 字符串1为:hehe
  14. D/Canopencommand: 字符串2为:wawa

4. 在JNI中调用实例化对象中的方法1:(使用自身对象,自身已被实例化)

JAVA层:测试对象

  1. public class CANopen {
  2. private static final String TAG = "CANopen";
  3.  
  4. static {
  5. Log.d(TAG, "static1");
  6. System.loadLibrary("Canopen-lib");
  7. Log.d(TAG, "static2");
  8. }
  9.  
  10. public native void testCallMethod();
  11.  
  12. private void JNIcallback(){
  13. Log.d(TAG, "这是JNI从C/C++回调JAVA实例化对象中的方法");
  14. }
  15.  
  16. private int JNIcallback2(int a, byte b){
  17. Log.d(TAG, "整型="+a+";字节="+b);
  18. return ;
  19. }
  20.  
  21. private String JNIcallback3(int a, String b, byte[]c){
  22. Log.d(TAG, "整型="+a);
  23. Log.d(TAG,"字符串="+b);
  24. Log.d(TAG,"数组长度="+c.length);
  25. return new String("hello world");
  26. }
  27. }

JAVA层:

  1. Log.d(TAG, "onCreate1");
  2. caNopen.testCallMethod();
  3. Log.d(TAG, "onCreate2");

JNI层:

  1. JNIEXPORT void JNICALL Java_com_aplex_canopen_CANopen_testCallMethod
  2. (JNIEnv *env, jobject obj){
  3. jboolean isCopy;
  4.  
  5. //1. 先调用一个比较简单的(无参无返回)
  6. LOGD("##########第一个############");
  7. jclass jc = env->GetObjectClass(obj); //通过实例化对象找到类
  8. jmethodID id = env->GetMethodID(jc, "JNIcallback", "()V"); //找到实例化对象里函数的ID
  9. env->CallVoidMethod(obj, id); //调用obj这个实例化对象里的函数id
  10.  
  11. //2. 调用稍微复杂点的(基本类型参数和返回值)
  12. LOGD("##########第二个############");
  13. jclass jc2 = env->GetObjectClass(obj); //通过实例化对象找到类
  14. jmethodID id2 = env->GetMethodID(jc2, "JNIcallback2", "(IB)I"); //找到实例化对象里函数的ID
  15. jint i = env->CallIntMethod(obj, id2, 0x1234, ); //调用obj这个实例化对象里的函数id
  16. LOGD("JNI中返回参数=%d",i);
  17.  
  18. //3. 调用一个比较复杂的(带对象类型参数和返回值)
  19. LOGD("##########第三个############");
  20. jclass jc3 = env->GetObjectClass(obj); //通过实例化对象找到类
  21. jmethodID id3 = env->GetMethodID(jc3, "JNIcallback3", "(ILjava/lang/String;[B)Ljava/lang/String;"); //找到实例化对象里函数的ID
  22. //创建byte数组,注意:无法赋值!!!
  23. jbyteArray byteArray = env->NewByteArray();
  24. int len = env->GetArrayLength(byteArray);
  25. //创建一个string并赋值
  26. jstring jstr = env->NewStringUTF("fuck!!");
  27. jstring str = (jstring)env->CallObjectMethod(obj, id3, , jstr,byteArray); //调用obj2这个实例化对象里的函数id,返回值是对象,要进行强制转换
  28. const char* cstr = env->GetStringUTFChars(str,&isCopy);
  29. LOGD("JNI中打印:%s", cstr);
  30. env->ReleaseStringUTFChars(str, cstr);
  31.  
  32. }

结果:

  1. D/MainActivity: onCreate1
  2. D/Canopencommand: ##########第一个############
  3. D/CANopen: 这是JNIC/C++回调JAVA实例化对象中的方法
  4. D/Canopencommand: ##########第二个############
  5. D/CANopen: 整型=;字节=
  6. D/Canopencommand: JNI中返回参数=
  7. D/Canopencommand: ##########第三个############
  8. D/CANopen: 整型=
  9. D/CANopen: 字符串=fuck!!
  10. D/CANopen: 数组长度=
  11. D/Canopencommand: JNI中打印:hello world
  12. D/MainActivity: onCreate2

5. 在JNI中调用实例化对象中的方法2:(新建实例化对象,修改对象的属性值,调用对象方法)

需要实例化的对象:

  1. package com.aplex.canopen;
  2.  
  3. import android.util.Log;
  4.  
  5. public class TestClass {
  6. private String TAG = "TestClass";
  7. private int a;
  8. TestClass(){
  9. a = ;
  10. Log.d(TAG,"调用无参构造函数");
  11. }
  12.  
  13. TestClass(int a){
  14. this.a = a;
  15. Log.d(TAG,"调用有参构造函数="+a);
  16. }
  17.  
  18. public int getValue(){
  19. Log.d(TAG, "a="+this.a);
  20. return this.a;
  21. }
  22. }

JAVA层:

  1. Log.d(TAG, "onCreate1");
  2. caNopen.testCallMethod2();
  3. Log.d(TAG, "onCreate2");

JNI层:

  1. JNIEXPORT void JNICALL Java_com_aplex_canopen_CANopen_testCallMethod2
  2. (JNIEnv *env, jobject obj){
  3. //1. 调用无参构造函数、修改变量(属性)值
  4. LOGD("##########调用无参构造函数############");
  5. jclass jc = env->FindClass("com/aplex/canopen/TestClass"); //找到类,该类未被实例化
  6. jmethodID initID = env->GetMethodID(jc, "<init>", "()V");//找到构造函数的id;注意:构造函数"<init>"为固定值
  7. jobject mobj = env->NewObject(jc, initID); //实例化一个对象
  8.  
  9. jmethodID funcID = env->GetMethodID(jc, "getValue", "()I"); //拿到方法的ID
  10. jint i = env->CallIntMethod(mobj, funcID); //调用方法
  11. LOGD("修改前查看函数返回的a=%d",i);
  12. jfieldID fieldID = env->GetFieldID(jc, "a", "I"); //拿到变量(属性)的ID
  13. jint ii = env->GetIntField(mobj, fieldID);
  14. LOGD("查看拿到的值a=%d",ii);
  15. ii = ;
  16. env->SetIntField(mobj, fieldID, ii);
  17. jint iii = env->CallIntMethod(mobj, funcID); //再次调用查看是否修改属性值
  18. LOGD("修改后查看函数返回的a=%d",iii);
  19.  
  20. //2. 调用有参构造函数
  21. LOGD("##########调用有参构造函数############");
  22. jclass jc2 = env->FindClass("com/aplex/canopen/TestClass");
  23. jmethodID initID2 = env->GetMethodID(jc2, "<init>", "(I)V"); //注意这里:"(I)V"
  24. jobject mobj2 = env->NewObject(jc2, initID2, );
  25. jmethodID funcID2 = env->GetMethodID(jc2, "getValue", "()I");
  26. jint i2 = env->CallIntMethod(mobj2, funcID2);
  27. LOGD("a=%d",i2);
  28. }

结果:

  1. D/MainActivity: onCreate1
  2. D/Canopencommand: ##########调用无参构造函数############
  3. D/TestClass: 调用无参构造函数
  4. D/TestClass: a=
  5. D/Canopencommand: 修改前查看函数返回的a=
  6. D/Canopencommand: 查看拿到的值a=
  7. D/TestClass: a=
  8. D/Canopencommand: 修改后查看函数返回的a=
  9. D/Canopencommand: ##########调用有参构造函数############
  10. D/TestClass: 调用有参构造函数=
  11. D/TestClass: a=
  12. D/Canopencommand: a=
  13. D/MainActivity: onCreate2

6. 异常处理

JAVA层:

  1. caNopen.testException();

JNI层:

  1. JNIEXPORT void JNICALL Java_com_aplex_canopen_CANopen_testException
  2. (JNIEnv *env, jobject obj){
  3. jclass jc = env->FindClass("java/io/IOException");
  4. env->ThrowNew(jc, "异常测试");
  5.  
  6. }

结果:

  1. E/AndroidRuntime: FATAL EXCEPTION: main
  2. Process: com.aplex.canopen, PID:
  3. java.lang.RuntimeException: Unable to start activity ComponentInfo{com.aplex.canopen/com.aplex.canopen.MainActivity}: java.io.IOException: 异常测试
  4. at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:)
  5. at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:)
  6. at android.app.ActivityThread.-wrap11(ActivityThread.java)
  7. at android.app.ActivityThread$H.handleMessage(ActivityThread.java:)
  8. at android.os.Handler.dispatchMessage(Handler.java:)
  9. at android.os.Looper.loop(Looper.java:)
  10. at android.app.ActivityThread.main(ActivityThread.java:)
  11. at java.lang.reflect.Method.invoke(Native Method)
  12. at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:)
  13. at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:)
  14. Caused by: java.io.IOException: 异常测试
  15. at com.aplex.canopen.CANopen.testException(Native Method)
  16. at com.aplex.canopen.MainActivity.onCreate(MainActivity.java:)
  17. at android.app.Activity.performCreate(Activity.java:)
  18. at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:)
  19. at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:)
  20. at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:) 
  21. at android.app.ActivityThread.-wrap11(ActivityThread.java) 
  22. at android.app.ActivityThread$H.handleMessage(ActivityThread.java:) 
  23. at android.os.Handler.dispatchMessage(Handler.java:) 
  24. at android.os.Looper.loop(Looper.java:) 
  25. at android.app.ActivityThread.main(ActivityThread.java:) 
  26. at java.lang.reflect.Method.invoke(Native Method) 
  27. at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:) 
  28. 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. C++(指针和高级指针)-上篇

    [在指针中存储地址] int *pAge=nullptr; //将PAge声明为int指针,即用于存储int变量的地址 如果将指针初始化为0或者NUll,以后必须将变量的地址赋给它,如下例代码: ; ...

  2. 开源一款强大的文件服务组件(QJ_FileCenter)(系列二 安装说明)

    系列文章 1. 开源一款强大的文件服务组件(QJ_FileCenter)(系列一) 2. 开源一款强大的文件服务组件(QJ_FileCenter)(系列二 安装说明) 3. 开源一款强大的文件服务组件 ...

  3. Android Library 使用规则

    1. 一个项目必须声明为 is library.使用该 library 的项目导入该 library. 2. library 的 manifect 中 activity 的声明需明确包名以避免找不到. ...

  4. 索引+sql优化

    索引的概念: 索引是提高查询速度的一种手段.索引有很多种,以下是索引树的结构 要求查询出薪资大于5000的雇员信息,只要在树中找到5000的节点,直接查询该节点右边的数据即可,左边就不用管了,这样提高 ...

  5. Python3.5 学习四

    装饰器 定义:本质是函数,装饰其他函数,即为其他函数添加附加功能的 原则: 1 不能修改被装饰函数的源代码 2 不能改变被装饰函数的调用方式(对于被装饰函数来说完全透明,不会受影响) 实现装饰器功能的 ...

  6. 【文文殿下】后缀自动机(Suffix Automaton,SAM)学习笔记

    前言 后缀自动机是一个强大的数据结构,能够解决很多字符串相关的(String-related)问题. 例如:他可以查询一个字符串在另一个字符串中出现的所有子串,以及查询一个字符串中本质不同的字符串的个 ...

  7. Python数据分析之文本处理词频统计

    1.项目背景: 原本计划着爬某房产网站的数据做点分析, 结果数据太烂了,链家网的数据干净点, 但都是新开楼盘,没有时间维度,分析意义不大. 学习的步伐不能ting,自然语言处理还的go on 2.分析 ...

  8. SpringData JPA实现CRUD,分页与多参数排序

    Spring Data 项目的目的是为了简化构建基于 Spring 框架应用的数据访问计数,包括非关系数据库.Map-Reduce 框架.云数据服务等等,SpringData JPA是简化创建 JPA ...

  9. 给对象和函数添加method方法

    蝴蝶书中有一个method方法,用来给函数定义方法.看了之后,想着能不能给对象也定义方法呢?. 下面的代码可以实现给函数定义方法: //Function method Function.prototy ...

  10. 10分钟教你用Python打造天气机器人+关键字自动回复+定时发送

    01 前言 Hello,各位小伙伴.自上次我们介绍了Python实现天气预报的功能以后,那个小程序还有诸多不完善的地方,今天,我们再次来完善一下我们的小程序.比如我们想给机器人发“天气”等关键字,它就 ...