LOG引入

#include <android/log.h>#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "com.droider.jnimethods", __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "com.droider.jnimethods", __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "com.droider.jnimethods", __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, "com.droider.jnimethods", __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "com.droider.jnimethods", __VA_ARGS__)

最简单的Jni方法

/** Class:     com_xiaomakj_hellogcc_TestJniMethods* Method:    nativeMethod* Signature: ()Ljava/lang/String;*/
JNIEXPORT jstring JNICALL Java_com_xiaomakj_hellogcc_TestJniMethods_nativeMethod(JNIEnv * env , jobject object){const char * chs = "你好!NativeMethod";return (*env)->NewStringUTF(env, chs);}

或者

jstring stoJstring( JNIEnv* env, const char* pat )
{jclass strClass = (*env)->FindClass(env, "java/lang/String");jmethodID ctorID =  (*env)->GetMethodID(env,strClass, "<init>", "([BLjava/lang/String;)V");jbyteArray bytes = (*env)->NewByteArray(env, strlen(pat));(*env)->SetByteArrayRegion(env, bytes, 0, strlen(pat), pat);jstring encoding = (*env)->NewStringUTF(env, "GB2312");return (jstring)(*env)->NewObject(env,strClass, ctorID, bytes, encoding);
}

对应native方法

public native String nativeMethod();

加载一个本地类

    int version = (*env)->GetVersion(env);//获JNI版本 LOGE("GetVersion() --> jni version:%2x", version);jclass build_class = (*env)->FindClass(env, "android/os/Build");  //加载一个本地类jfieldID brand_id = (*env)->GetStaticFieldID(env,           //获取类的静态字段IDbuild_class, "MODEL", "Ljava/lang/String;");jstring brand_obj = (jstring)(*env)->GetStaticObjectField(env,  //获取类的静态字段的值ֵbuild_class, brand_id);//__asm__ ("bkpt");//raise(SIGTRAP);const char *nativeString = (*env)->GetStringUTFChars(env, brand_obj, 0); //通过jstring生成char*LOGE("GetStringUTFChars() --> MODEL:%s", nativeString);LOGE("GetStaticFieldID() --> %s", nativeString);LOGE("ReleaseStringUTFChars() --> %s", nativeString);(*env)->ReleaseStringUTFChars(env, brand_obj, nativeString); //释放GetStringUTFChars()生成的char*
GetVersion() --> jni version:10006
GetStringUTFChars() --> MODEL:vivo X9i
GetStaticFieldID() --> vivo X9i
ReleaseStringUTFChars() --> vivo X9i

初始化本地对象

    jclass test_class = (*env)->FindClass(env, "com/droider/jnimethods/TestClass");//空参构造jmethodID constructor = (*env)->GetMethodID(env, test_class, "<init>", "()V"); //获取构造函数jobject obj = (*env)->NewObject(env, test_class, constructor);  //创建一个对象

操纵成员变量

//StringjfieldID stringfieldID = (*env)->GetFieldID(env,  //获取String类型的字段test_class, "aStringField", "Ljava/lang/String;");jstring stringfieldValue = (jstring)(*env)->GetObjectField(env,    //获取String字段的值ֵobj, stringfieldID);const char *stringValue = (*env)->GetStringUTFChars(env,stringfieldValue, 0);LOGE("GetObjectField() --> aStringField:%s", stringValue);  //int        jfieldID intfieldID = (*env)->GetFieldID(env,  //获取int类型的字段test_class, "aIntField", "I");jint fieldValue = (*env)->GetIntField(env, obj, intfieldID); //获取int字段的值ֵLOGV("GetIntField() --> aField:%d", fieldValue);(*env)->SetIntField(env, obj, intfieldID, (jint)123); // 设置int字段的值ֵfieldValue = (*env)->GetIntField(env, obj, intfieldID);LOGV("SetIntField() --> aField:%d", fieldValue);

获取父类

jclass parent_class = (*env)->GetSuperclass(env, test_class);
LOGV("GetSuperclass() --> ");       

JNI常量 定义在jni.h当中

#define JNI_FALSE   0
#define JNI_TRUE    1#define JNI_VERSION_1_1 0x00010001
#define JNI_VERSION_1_2 0x00010002
#define JNI_VERSION_1_4 0x00010004
#define JNI_VERSION_1_6 0x00010006#define JNI_OK          (0)         /* no error */
#define JNI_ERR         (-1)        /* generic error */
#define JNI_EDETACHED   (-2)        /* thread detached from the VM */
#define JNI_EVERSION    (-3)        /* JNI version error */#define JNI_COMMIT      1           /* copy content, do not free buffer */
#define JNI_ABORT       2           /* free buffer w/o copying back */

EnsureLocalCapacity 检测是否还可以创建5个局部引用 https://blog.csdn.net/xyang81/article/details/44873769)

  // 保证至少可以创建3个局部引用(str_array,cls_string,obj_str)if ((*env)->EnsureLocalCapacity(env, 3) != JNI_OK) {return NULL;}

操作本地方法

if(JNI_OK == (*env)->EnsureLocalCapacity(env, 5)){ //检测是否还可以创建5个局部引用LOGV("EnsureLocalCapacity() --> ensure 5 locals");jmethodID obj2_voidmethod = (*env)->GetMethodID(env, //获取一个void方法test_class, "aVoidMethod", "()V");(*env)->CallVoidMethod(env, obj, obj2_voidmethod);LOGV("CallVoidMethod()");jmethodID obj2_Staticmethod = (*env)->GetStaticMethodID(env,  //获取static方法test_class, "aStaticMethod", "(Ljava/lang/String;)V");LOGV("GetStaticMethodID()");const char *fromJni = "this string from jni";jstring jstr_static = (*env)->NewStringUTF(env, fromJni);(*env)->CallStaticVoidMethod(env, test_class, obj2_Staticmethod, jstr_static); //调用一个静态方法
}

MonitorEnter类似于JAVA的synchronized成对存在

 (*env)->MonitorEnter(env, obj); //同步操作(*env)->MonitorExit(env, obj);

操作String

//获取String
jmethodID obj2_chinesemethod = (*env)->GetMethodID(env,  //传递中文字符串test_class, "getChineseString", "()Ljava/lang/String;");
jstring obj2_chinesejstring = (jstring)(*env)->CallObjectMethod(env, obj, obj2_chinesemethod);
jsize chinese_size = (*env)->GetStringLength(env, obj2_chinesejstring);
LOGV("GetStringLength() --> %d", chinese_size);//GetStringRegion http://wiki.jikexueyuan.com/project/jni-ndk-developer-guide/string.html
//为这个字符串分配空间 0:statr,3:len,buff_jchar:end
jchar buff_jchar[4] = {0};
(*env)->GetStringRegion(env, obj2_chinesejstring, 0, 3, buff_jchar);
LOGV("GetStringRegion() -->");

jStrinfg to jchar

 const jchar * obj2_chinesechars = (*env)->GetStringChars(env, obj2_chinesejstring, NULL);jstring new_chinesestring = (*env)->NewString(env, obj2_chinesechars, chinese_size);

调用本地方法 并释放String

jmethodID obj2_Staticmethod = (*env)->GetStaticMethodID(env,  //获取static方法test_class, "aStaticMethod", "(Ljava/lang/String;)V");
LOGE("GetStaticMethodID()");
(*env)->CallStaticVoidMethod(env, test_class, obj2_Staticmethod, new_chinesestring); //调用一个静态方法
(*env)->ReleaseStringChars(env, obj2_chinesejstring, obj2_chinesechars); //释放GetStringChars获取的jchar*LOGV("CallStaticVoidMethod()");

Jni调用JAVA返回计算结果

jmethodID obj2_sqrtmethod = (*env)->GetStaticMethodID(env,  //获取一个static方法test_class, "sqrt", "(I)I");
jint int_sqrt = (*env)->CallStaticIntMethod(env, //计算5的平方test_class, obj2_sqrtmethod, (jint)5);
LOGE("CallStaticIntMethod() -->5 sqrt is:%d", int_sqrt);

java代码

public static int sqrt(int x){return x * x;
}

IsAssignableFrom:

判断该类是否是本类或子类 是则返回true

https://www.jb51.net/article/103114.htm

抛出一个异常

if(JNI_TRUE == (*env)->IsAssignableFrom(env, test_class, parent_class)){LOGV("IsAssignableFrom() --> yes");} else {jclass newExceptionClazz = (*env)->FindClass(env,"java/lang/RuntimeException"); //实例化一个异常if(newExceptionClazz != NULL)(*env)->ThrowNew(env, newExceptionClazz,"这里永远不会被执行的!");LOGE("ThrowNew()");}

获取对象的类

 jclass obj_clazz = (*env)->GetObjectClass(env, obj); //获取对象的类if(JNI_TRUE == (*env)->IsInstanceOf(env, obj, obj_clazz)){LOGE("IsInstanceOf() --> Yes");} else {(*env)->FatalError(env, "fatal error!"); //抛出致命错误LOGE("FatalError()");}

FatalError致命错误

  (*env)->FatalError(env, "fatal error!");

创建全局和局部引用 相当于 new

(*env)->PushLocalFrame(env, 2); //申请局部引用空间,增加局部引用的管理jobject obj_localref = (*env)->NewLocalRef(env, obj); //创建一个局部引用jobject obj_globalref = (*env)->NewGlobalRef(env, obj); //创建一个全局引用LOGV("PushLocalFrame()");LOGV("NewLocalRef()");LOGV("NewGlobalRef()");if (JNI_TRUE == (*env)->IsSameObject(env, obj_localref, obj_globalref)){LOGV("IsSameObject() --> Yes");}(*env)->DeleteLocalRef(env, obj_localref);   //删除一个局部引用(*env)->DeleteGlobalRef(env, obj_globalref); //删除一个全局引用(*env)->PopLocalFrame(env, NULL);LOGV("DeleteLocalRef()");LOGV("DeleteGlobalRef()");LOGV("PopLocalFrame()");

调用子类成员和方法

注意:CallNonvirtualVoidMethod方法 第三个参数为指定类类型

jclass sub_class = (*env)->FindClass(env,"com/droider/jnimethods/TestSubClass"); //查询子类jobject sub_obj = (*env)->AllocObject(env, sub_class);jmethodID sub_methodID = (*env)->GetMethodID(env,sub_class, "aVoidMethod", "()V");(*env)->CallNonvirtualVoidMethod(env,sub_obj, sub_class, sub_methodID); //调用子类的方法(*env)->CallNonvirtualVoidMethod(env,sub_obj, test_class, sub_methodID); //根据调用类的不同调用父类的方法jfieldID sub_fieldID = (*env)->GetStaticFieldID(env, //获取子类静态字段sub_class, "subFloatField", "F");(*env)->SetStaticFloatField(env, sub_class, sub_fieldID, (jfloat)33.88f);LOGV("SetStaticFloatField() --> %.2f",(*env)->GetStaticFloatField(env, sub_class, sub_fieldID));

异常抓取
https://blog.csdn.net/arui319/article/details/2178619

    jthrowable throwable = (*env)->ExceptionOccurred(env);//判断是否包含异常 有则清除和打印异常if (throwable){     //有异常发生,还可以使用ExceptionCheck()函数来判断(*env)->ExceptionDescribe(env);(*env)->ExceptionClear(env);LOGE("ExceptionOccurred()");}

int 数组操作

jintArray int_array = (*env)->NewIntArray(env, 5);  //创建int数组
LOGV("NewIntArray() --> %d", (*env)->GetArrayLength(env, int_array)); //获取数组长度
const jint ints[] = {11, 12, 13, 14, 15};
(*env)->SetIntArrayRegion(env, int_array, 0, 5, ints); //设置数组一个范围的值ֵ
LOGV("SetIntArrayRegion() --> %d,%d,%d,%d,%d",ints[0], ints[1], ints[2], ints[3], ints[4]);
jint ints2[2] = {0, 0};
(*env)->GetIntArrayRegion(env, int_array, 1, 2, ints2); //获取数组一个范围的值
LOGV("GetIntArrayRegion() --> %d,%d", ints2[0], ints2[1]);
jint* array_ints = (*env)->GetIntArrayElements(env, int_array, NULL); //获取指向所有元素的指针
LOGV("GetIntArrayElements() --> %d,%d,%d,%d,%d",array_ints[0], array_ints[1], array_ints[2], array_ints[3], array_ints[4]);
(*env)->ReleaseIntArrayElements(env, int_array, array_ints, 0); //释放指向所有元素的指针
LOGV("ReleaseIntArrayElements()");

String 数组操作

jclass class_string = (*env)->FindClass(env, "java/lang/String");
jarray string_array = (*env)->NewObjectArray(env, 3, class_string, 0); //创建String数组
LOGV("NewObjectArray()");
jsize array_size = (*env)->GetArrayLength(env, string_array);
LOGV("GetArrayLength() --> %d", array_size);
jstring array_string1 = (*env)->NewStringUTF(env, "one");
char buff_char[4] = {0};
(*env)->GetStringUTFRegion(env, array_string1, 0, 3, buff_char);
LOGV("GetStringUTFRegion() --> %s", buff_char);
(*env)->SetObjectArrayElement(env, string_array, 0, array_string1); //设置数组元素的值
LOGV("SetObjectArrayElement() --> one");
array_string1 = (jstring)(*env)->GetObjectArrayElement(env, string_array, 0); //获取数组元素的值
const char* array_elemchars = (*env)->GetStringUTFChars(env, array_string1, NULL);
LOGV("GetObjectArrayElement() --> %s", array_elemchars);
(*env)->ReleaseStringUTFChars(env, array_string1, array_elemchars);

JNI_OnLoad和JNI_OnUnLoad:
JNI的内部方法,RegisterNatives加载本地方法,动态引入native方法,也就是在.h文件中并未实现申明的函数在JNI中动态添加

JNIEnv *g_env;
jclass native_class;
#ifndef NELEM //计算结构元素个数
# define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
#endifstatic JNINativeMethod methods[] = {{"newJniThreads", "(I)V", (void*)newJniThreads}
};jint JNI_OnLoad(JavaVM* vm, void* reserved){if(JNI_OK != (*vm)->GetEnv(vm, (void**)&g_env, JNI_VERSION_1_6)){ //加载指定版本的JNI  对应 int version = (*env)->GetVersion(env);return -1;}LOGV("JNI_OnLoad()");native_class = (*g_env)->FindClass(g_env, "com/xiaomakj/hellogcc/TestJniMethods");if (JNI_OK ==(*g_env)->RegisterNatives(g_env,   //注册未声明的本地方法native_class, methods, NELEM(methods))){LOGV("RegisterNatives() --> nativeMethod() ok");} else {LOGE("RegisterNatives() --> nativeMethod() failed");return -1;}return JNI_VERSION_1_6;
}void JNI_OnUnLoad(JavaVM* vm, void* reserved){LOGV("JNI_OnUnLoad()");(*g_env)->UnregisterNatives(g_env, native_class);LOGV("UnregisterNatives()");
}

newJniThreads方法 注意:
1.方法名较 Java_com_droider_jnimethods_TestJniMethods_test短得多
2.这里方法需要事先申明 否则将该方法放在JNI_OnLoad之前

#include <pthread.h>//引入线程头文件
JNIEXPORT void newJniThreads(JNIEnv* env, jobject obj, jint nums){}

线程操作
注意:
1.代码的顺序 thread_func在上面
2.GetJavaVM方法获取全集JVM对象,控制线程的创建


#include <pthread.h>    //导入线程.h
JavaVM *g_vm;   //下面多线程程序用到
pthread_mutex_t thread_mutex;void *thread_func(void *arg){JNIEnv *env;pthread_mutex_lock(&thread_mutex);if (JNI_OK != (*g_vm)->AttachCurrentThread(g_vm, &env, NULL)){LOGE("AttachCurrentThread() failed");return NULL;}LOGE("AttachCurrentThread() --> thread:%d", (jint)arg);(*g_vm)->DetachCurrentThread(g_vm);LOGE("DetachCurrentThread() --> thread:%d", (jint)arg);pthread_mutex_unlock(&thread_mutex);pthread_exit(0);return NULL;
}JNIEXPORT void newJniThreads(JNIEnv* env, jobject obj, jint nums){(*env)->GetJavaVM(env, &g_vm);  //保存全局JavaVMLOGE("GetJavaVM()");pthread_t* pt = (pthread_t*)malloc(sizeof(pthread_t)* nums);pthread_mutex_init(&thread_mutex, NULL);int i;for (i = 0 ; i < nums; i++){pthread_create(&pt[i], NULL, &thread_func, (void*)i); //创建线程}free(pt);
}

分析一下 pthread_create:

 pthread_create(&pt[i], NULL, &thread_func, (void*)i); //创建线程第一个参数pt代表了数组pt的首地址指正,pt[i]也就是申请的第i个指针&pt[i]即取地址值

参考

https://blog.csdn.net/fx677588/article/details/74857473

试验可参考

https://blog.csdn.net/oyhb_1992/article/details/77162326?locationNum=9&fps=1

帮助理解int a[5];

a的类型是int[5]   数组&a的类型是int(*)[5]  指针——指向int[5]数组的指针&a[0]的类型是int*    指针——指向int类型的指针

malloc和free成对存在:动态分配和释放内存
malloc返回的是分配内存的地址

pthread_mutex_lock 锁

pthread_mutex_lock(&thread_mutex);  pthread_mutex_unlock(&thread_mutex);
pthread_exit(0)

字节缓冲区


JNIEXPORT jobject allocNativeBuffer(JNIEnv* env, jobject obj, jlong size){void* buffer = malloc(size);jobject directBuffer = (*env)->NewDirectByteBuffer(env, buffer, size);LOGE("NewDirectByteBuffer() --> %d", (int)size);return directBuffer;
}JNIEXPORT void freeNativeBuffer(JNIEnv* env, jobject obj, jobject bufferRef)
{void *buffer = (*env)->GetDirectBufferAddress(env, bufferRef);strcpy(buffer, "123");LOGE("GetDirectBufferAddress() --> %s", buffer);free(buffer);
}

JAVA调用

 Object obj = methods.allocNativeBuffer(16L); //分配字节缓冲区methods.freeNativeBuffer(obj);  //释放字节缓冲区

源码链接:https://pan.baidu.com/s/1_EhtJ2RoLCmtIu1pV5CdAQ 密码:sywq
文件路径:
++源代码(韦生强)\源代码\chapter7\7.6\7.6.2\jnimethods\jni++

JNI数据与方法操作实例相关推荐

  1. 大数据——MongoDB数据库操作实例

    大数据--四种数据库(MySQL,HBase,MongoDB,Redis)操作实例 问题描述: student文档如下: 1. 根据上面给出的文档信息,用MongoDB模式设计student集合. a ...

  2. 大数据——MySQL数据库操作实例

    大数据--四种数据库(MySQL,HBase,MongoDB,Redis)操作实例 问题描述: Student学生表 1. 根据上面给出的表格,利用MySQL5.7设计出student学生表格; a) ...

  3. 大数据——HBase数据库操作实例

    大数据--四种数据库(MySQL,HBase,MongoDB,Redis)操作实例 问题描述: Student学生表 1. 根据上面给出的表格,用Hbase Shell模式设计student学生表格. ...

  4. java $.getjson_JQuery 获取json数据$.getJSON方法的实例代码

    jQuery系列 第八章 jQuery框架Ajax模块 第八章 jQuery框架Ajax模块 8.1 jQuery框架中的Ajax简介 Ajax技术的核心是XMLHTTPRequest对象,该对象是A ...

  5. [转载] python复数类型-Python 复数属性和方法操作实例

    参考链接: Python中的复数1(简介) 复数是由一个实数和一个虚数组合构成,表示为:x+yj 一个复数时一对有序浮点数 (x,y),其中 x 是实数部分,y 是虚数部分. Python 语言中有关 ...

  6. Python 复数属性和方法操作实例

    复数是由一个实数和一个虚数组合构成,表示为:x+yj 一个复数时一对有序浮点数 (x,y),其中 x 是实数部分,y 是虚数部分. Python 语言中有关复数的概念: 1.虚数不能单独存在,它们总是 ...

  7. Python复数属性和方法操作实例

    无意中发现了一个很好的软件测试网站,忍不住分享一下给大家.觉得很实用,所以分享给大家.点这里可以跳转到教程. #coding=utf8 ''' 复数是由一个实数和一个虚数组合构成,表示为:x+yj 一 ...

  8. python语言复数类型实部可以为0_[转载] python复数类型-Python 复数属性和方法操作实例...

    参考链接: Python中的复数1(简介) 复数是由一个实数和一个虚数组合构成,表示为:x+yj 一个复数时一对有序浮点数 (x,y),其中 x 是实数部分,y 是虚数部分. Python 语言中有关 ...

  9. php html转成数组,PHP_php将HTML表格每行每列转为数组实现采集表格数据的方法,本文实例讲述了php将HTML表格每 - phpStudy...

    php将HTML表格每行每列转为数组实现采集表格数据的方法 本文实例讲述了php将HTML表格每行每列转为数组实现采集表格数据的方法.分享给大家供大家参考.具体如下: 下面的php代码可以将HTML表 ...

  10. php addall,ThinkPHP3.2框架使用addAll()批量插入数据的方法

    这篇文章主要介绍了ThinkPHP3.2框架使用addAll()批量插入数据的方法,结合实例形式分析了thinkPHP针对单条数据插入及批量数据插入操作的相关实现技巧,需要的朋友可以参考下 本文实例讲 ...

最新文章

  1. codevs 2879 堆的判断
  2. Android 的 ramdisk.img、system.img、userdata.img 作用说明,以及UBoot 系统启动过程
  3. delphi xe http 收不到反馈消息_好消息接二连三!苹果将在双·11当天举办发布会_笔记本新闻...
  4. 火狐标签在中间_在Firefox中保留未使用的标签
  5. linux结束所有任务命令行,Linux基础命令(15)定时任务
  6. openjdk:8u22-jre-alpine在java开发中的NullPointerException错误解决方案
  7. 13.SpringMVC核心技术-异常处理
  8. ace缓存扩展接口_跟普通固态硬盘有何区别?群晖发布NAS专用SSD和扩展卡
  9. mysql处理sql时间格式_mysql 处理日期格式
  10. word、PDF、html、chm 文件的转换
  11. jar包运行utf-8格式
  12. 改善用户体验 Web前端优化策略总结.........
  13. k3梅林刷官改变砖_K3 op强刷回官改变砖,TTL救砖也不行,请大神分析下是不是要换内存了...
  14. linux 小度 驱动_360WiFi 小度WiFi 无线网卡驱动下载
  15. springboot+vue前后端分离实现企业人事管理系统
  16. 计算机频率原理,频率计工作原理介绍
  17. 论需求分析方法及应用--系统分析师
  18. GitLab(三)创建用户
  19. c语言某年某月某日的天数,输入某年某月某日,判断这一天是这一年的第几天...
  20. 小C实例也有大梦想——自定义strlen函数

热门文章

  1. Windows电脑多屏显示器设置方法怎么找回副屏显示器隐藏的敬业签软件
  2. PageObject(PO)设计模式在 UI 自动化中的实践总结(以 QQ 邮箱登陆为例)
  3. Android Go项目 来电铃声与UI不同步问题
  4. 男孩取名分享:光彩夺目、聪明机灵的男孩名
  5. c语言数组文曲星猜数游戏编程,第7章 数组-8数组的其他应用——文曲星猜数游戏...
  6. 我很忙,但对你随时有空!
  7. Oracle between and
  8. android手机电视下载软件安装失败,新买的电视无法安装第三方软件?方法汇总来了,解决99%的问题...
  9. vue项目如何部署?history与hash模式部署时的区别
  10. POR BOR LVD