JNI数据与方法操作实例
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数据与方法操作实例相关推荐
- 大数据——MongoDB数据库操作实例
大数据--四种数据库(MySQL,HBase,MongoDB,Redis)操作实例 问题描述: student文档如下: 1. 根据上面给出的文档信息,用MongoDB模式设计student集合. a ...
- 大数据——MySQL数据库操作实例
大数据--四种数据库(MySQL,HBase,MongoDB,Redis)操作实例 问题描述: Student学生表 1. 根据上面给出的表格,利用MySQL5.7设计出student学生表格; a) ...
- 大数据——HBase数据库操作实例
大数据--四种数据库(MySQL,HBase,MongoDB,Redis)操作实例 问题描述: Student学生表 1. 根据上面给出的表格,用Hbase Shell模式设计student学生表格. ...
- java $.getjson_JQuery 获取json数据$.getJSON方法的实例代码
jQuery系列 第八章 jQuery框架Ajax模块 第八章 jQuery框架Ajax模块 8.1 jQuery框架中的Ajax简介 Ajax技术的核心是XMLHTTPRequest对象,该对象是A ...
- [转载] python复数类型-Python 复数属性和方法操作实例
参考链接: Python中的复数1(简介) 复数是由一个实数和一个虚数组合构成,表示为:x+yj 一个复数时一对有序浮点数 (x,y),其中 x 是实数部分,y 是虚数部分. Python 语言中有关 ...
- Python 复数属性和方法操作实例
复数是由一个实数和一个虚数组合构成,表示为:x+yj 一个复数时一对有序浮点数 (x,y),其中 x 是实数部分,y 是虚数部分. Python 语言中有关复数的概念: 1.虚数不能单独存在,它们总是 ...
- Python复数属性和方法操作实例
无意中发现了一个很好的软件测试网站,忍不住分享一下给大家.觉得很实用,所以分享给大家.点这里可以跳转到教程. #coding=utf8 ''' 复数是由一个实数和一个虚数组合构成,表示为:x+yj 一 ...
- python语言复数类型实部可以为0_[转载] python复数类型-Python 复数属性和方法操作实例...
参考链接: Python中的复数1(简介) 复数是由一个实数和一个虚数组合构成,表示为:x+yj 一个复数时一对有序浮点数 (x,y),其中 x 是实数部分,y 是虚数部分. Python 语言中有关 ...
- php html转成数组,PHP_php将HTML表格每行每列转为数组实现采集表格数据的方法,本文实例讲述了php将HTML表格每 - phpStudy...
php将HTML表格每行每列转为数组实现采集表格数据的方法 本文实例讲述了php将HTML表格每行每列转为数组实现采集表格数据的方法.分享给大家供大家参考.具体如下: 下面的php代码可以将HTML表 ...
- php addall,ThinkPHP3.2框架使用addAll()批量插入数据的方法
这篇文章主要介绍了ThinkPHP3.2框架使用addAll()批量插入数据的方法,结合实例形式分析了thinkPHP针对单条数据插入及批量数据插入操作的相关实现技巧,需要的朋友可以参考下 本文实例讲 ...
最新文章
- codevs 2879 堆的判断
- Android 的 ramdisk.img、system.img、userdata.img 作用说明,以及UBoot 系统启动过程
- delphi xe http 收不到反馈消息_好消息接二连三!苹果将在双·11当天举办发布会_笔记本新闻...
- 火狐标签在中间_在Firefox中保留未使用的标签
- linux结束所有任务命令行,Linux基础命令(15)定时任务
- openjdk:8u22-jre-alpine在java开发中的NullPointerException错误解决方案
- 13.SpringMVC核心技术-异常处理
- ace缓存扩展接口_跟普通固态硬盘有何区别?群晖发布NAS专用SSD和扩展卡
- mysql处理sql时间格式_mysql 处理日期格式
- word、PDF、html、chm 文件的转换
- jar包运行utf-8格式
- 改善用户体验 Web前端优化策略总结.........
- k3梅林刷官改变砖_K3 op强刷回官改变砖,TTL救砖也不行,请大神分析下是不是要换内存了...
- linux 小度 驱动_360WiFi 小度WiFi 无线网卡驱动下载
- springboot+vue前后端分离实现企业人事管理系统
- 计算机频率原理,频率计工作原理介绍
- 论需求分析方法及应用--系统分析师
- GitLab(三)创建用户
- c语言某年某月某日的天数,输入某年某月某日,判断这一天是这一年的第几天...
- 小C实例也有大梦想——自定义strlen函数
热门文章
- Windows电脑多屏显示器设置方法怎么找回副屏显示器隐藏的敬业签软件
- PageObject(PO)设计模式在 UI 自动化中的实践总结(以 QQ 邮箱登陆为例)
- Android Go项目 来电铃声与UI不同步问题
- 男孩取名分享:光彩夺目、聪明机灵的男孩名
- c语言数组文曲星猜数游戏编程,第7章 数组-8数组的其他应用——文曲星猜数游戏...
- 我很忙,但对你随时有空!
- Oracle between and
- android手机电视下载软件安装失败,新买的电视无法安装第三方软件?方法汇总来了,解决99%的问题...
- vue项目如何部署?history与hash模式部署时的区别
- POR BOR LVD