Android学习笔记1-4--机制1--JNI
来源:互联网 发布:淘宝活动时间表 编辑:程序博客网 时间:2024/06/11 09:10
JNI简介
JNI:Java Native Interface。即Java函数和Native函数通过该接口可以互相调用。JNI层必须实现为动态库的形式,这样Java虚拟机才能加在并调用其的函数。
1) Java层对应类名为无要求,关键点是通过手动写代码加载进来的JNI库。
2) JNI层对应库名在不同底层平台下名称不一样,如linux下libXXX_jni.so和Windows下XXX_jni.dll。
3) Native层对应库名为去掉JNI库名的_jni而形成的名称。
JNI使用
Native函数使用分两大步:在Java层JNI库的加载和相关Native函数声明;在JNI层Native函数注册。
1.1) 在Java层JNI库的加载:
加载时机和加载地点为任何时候、任何地方均可,通行做法是在类起始的static语句块中加载。加载形式System.loadLibrary(“XXX_jni”)。系统会自动根据不同底层平台扩展成真实的JNI动态库文件名。
1.2) 在Java层Native函数声明:
Native函数为抽象函数。在函数名返回值前加上Native即可,有final要放在final前。
2) 在JNI层Native函数注册:
2.1) 静态注册
当Java层函数调用Native函数时,虚拟机会查找JNI库中对应静态注册JNI函数:Java函数找到对应的JNI函数是通过包名.类名.函数名的字符串转换(.转为_)而得到的。找不到就会报错;找到了就保存JNI层函数的函数指针供本次和以后使用。这种方法需要Java工具javah的参与,流程如下:a) 编写java代码形成.class文件。
b) 使用javah命令javah xxx.class -o yyy,会输出yyy.h的JNI层头文件(yyy的命名格式一般为包名_类名_class(.转为_),其声明了JNI层函数),再对其头文件实现JNI层对应的Native函数。2.2) 动态注册
当Java层加载JNI库完成时,虚拟机会调用JNI库中JNI_OnLoad函数开始动态注册JNI函数:JNI技术中叫JNINativeMethod的结构用来记录Java、Native函数与JNI函数一一对应的关系。AndroidRunTime类提供了注册函数工具registerNativeMethods操作该结构完成注册。虚拟机通过调用注册函数加载器JNI_OnLoad开始注册。
// JNINativeMethod结构定义typedef struct{ // Java中Native函数的名字,不用携带包和类名 const char* name; // Java中Native函数的签名,用字符串表示,是参数和返回值的组合 const char* signature; // JNI层对应函数的函数指针,他的类型为void*类型 void* fnPtr;}
// registerNativeMethods函数定义int registerNativeMethods(JNIEnv* env,const char* className,const JNINativeMethod* gMethods,int numMethods){ // 调用JNI层的jniRegisterNativeMethods函数 return jniRegisterNativeMethods(env,className,gMethods,numMethods);}// jniRegisterNativeMethods函数定义简介int jniRegisterNativeMethods(JNIEnv* env,const char* className,const JNINativeMethod* gMethods,int numMethods){ // 获取具体的类名。因JNINativeMethod中name非全路径名,多以要找寻是那个类 jclass clazz = (*env)->FindClass(env,className); ... // 调用JNIEnv的RegisterNatives函数注册关联关系 if((*env)->RegisterNatives(env,clazz,gMethods, numMethods)<0){ return -1; } return 0;}
// JNI_OnLoad函数例子jint JNI_OnLoad(JavaVM* vm,void* reserved){ // ...}
创建cpp文件内容结构如下:
a) 在里面定义个关于Java路径类的宏(指定要注册的类)以及定义个JNINativeMethod数组(指定要注册的函数)。
b) 实现JNI层对应的Native函数,编写注册函数包装器JNI_RegisterNativeMethods以及实现注册函数加载器JNI_OnLoad。
// NDEBUG宏是标准C中定义的宏(专门用来控制assert()的行为)// 如果定义了这个宏则assert不会起作用。要在<assert.h>之前不然禁用assert不会成功#define NDEBUG#include <assert.h>#include <stdlib.h>#include <jni.h>// 定义关于Java路径类的宏(指定要注册的类)#define JNIREG_CLASS "cn/test/andr/test/service/TestJNIImp"// 定义JNINativeMethod数组(指定要注册的函数)static JNINativeMethod JNIREG_METHODS[] = { { "getCPPString", "()Ljava/lang/String;", (void *) jni_getCPPString }};// JNI层对应的Native函数JNIEXPORT jstring JNICALL jni_getCPPString(JNIEnv *env, jclass clazz) { return (*env)->NewStringUTF(env, "hello world");}// 注册函数包装器JNI_RegisterNativeMethodsstatic int JNI_RegisterNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *gMethods, int numMethods) { jclass clazz = (*env)->FindClass(env, className); if (clazz == NULL) { return JNI_FALSE; } if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) { return JNI_FALSE; } return JNI_TRUE;}// 注册函数加载器JNI_OnLoadjint JNI_OnLoad(JavaVM *vm, void *reserved) { JNIEnv *env = NULL; jint JNI_VERSION = JNI_VERSION_1_4; if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION) != JNI_OK) { return -1; } assert(env != NULL); if (!JNI_RegisterNativeMethods(env, JNIREG_CLASS, JNIREG_METHODS, sizeof(JNIREG_METHODS) / sizeof(JNIREG_METHODS[0]))) {//注册 return -1; } return JNI_VERSION;}
JNI深入
类型转换和类型签名
暂时省略
引用类型和垃圾回收
暂时省略
JNIEnv和JavaVM
暂时省略
JNI的异常处理逻辑
暂时省略
一个简单的demo
- Android学习笔记1-4--机制1--JNI
- android JNI 学习笔记1
- Android JNI学习笔记1(Android Studio)
- android jni 学习1
- android JNI 学习笔记
- android JNI 学习笔记
- android jni 学习笔记
- android JNI 学习笔记
- Android JNI 学习笔记
- android JNI 学习笔记
- Android JNI学习笔记
- Android JNI 学习笔记
- Android JNI 学习笔记
- android-JNI学习记录(1)
- android jni 学习笔记2
- android学习笔记之JNI
- android JNI入门-学习笔记
- 学习Android JNI开发笔记
- 用Shell编程写一个能实现自动安装目录和运行游戏的脚本
- Tomcat相关问题
- 68-69_常用类_可视化日历程序
- Unity3D中 使模型变成变透明
- 配置JDK-1.8
- Android学习笔记1-4--机制1--JNI
- 34. OP-TEE中system call的实现
- BZOJ 2321 [BeiJing2011集训] 星器
- Android学习笔记2-1--组件0--Context
- Avro与JAVA
- Linux下修改Mysql的用户(root)的密码
- 自动布局Masonry的简单介绍
- Android学习笔记2-1--组件1--Application
- Linux进程间通信——使用信号量