JNI基础技术

2020-07-26  本文已影响0人  程序实现梦想

一.JNI概论

jni概述.jpg

二.库命名方式

1.Java:MediaScanner
2.JNI层:libmedia_jni.so。Android平台基本都采用“lib模块名_jin.so”的命名方式。
3.Native层对应的是:libmedia.so

三.加载JNI库

1.动态库:就是运行时加载的库。
2.加载:System.loadLibrary("media.jin")在实际加载的过程中libmedia_jni.so,在windows平台拓展为media.jni.dll。
3.声明有native修饰的函数。

四.注册JNI函数

1.静态方法:根据函数名来找对应的JNI函数。

整体流程:

(1).先编写Java代码,然后编译生成.class文件。
(2).使用Java的工具程序javah,如javah -o output packagename.classname这样就生成了一个叫output.h的JNI层头文件。其中packagename是Java代码编译后的class文件,而生成的output.h文件里,声明了对应的JNI层函数。注:这个头文件一般都会使用packagename_class.h的样式。
(3).弊端:
1.需要编译所有声明了natvie函数的Java类,每个生成的class文件都得用javah生成一个头文件。
2.javah生成的JNI函数特别长,书写起来不方便。
3.初次调用native函数时要根据函数名搜索对应的JNI层函数来建立联系关系,这样会影响运行效率。

2.动态注册

java native函数和JNI函数是一一对应的。在JNI技术中采用记录这种一一对应关系的是一个叫JNINativeMathod的结构,定义如下

typedef struct { 
const char * name;//java中函数的名字不用携带包的路径。
const * signature;//函数的签名信息,用字符串表示是参数类型和返回值类型的组合。
void * fnPtr;//JNI层对用的函数指针它是void * 类型。
} JNINativeMethod;

五.数据类型

JNI与Java对应数据类型.jpg

六.JNIEnv介绍

JNI是一个与线程相关的代表JNI环境的结构体。线程相关结构指向JNI函数指针数组,这个数组中存放了大量的JNI函数指针,这些指针指向了详细的JNI函数。


JNIEnv.jpg

注:调用JavaVM的AtttachCurrentThread函数就可得到这个线程的JNIEnvj结构替。调用JavaVM的DetachCurrentThread函数来释放对应资源。

七.通过JNIEnv操作jobject

1.jfieldID和jmethodID

通过JNIEnv等到:
jfieldID  GetFieldId(jclass clazz, const *name, const char *sig);
jmethodID GetMothodID(jclass clazz, const char *name, const char *sig);
其中jclass代表Java类,name表示成员函数或成员变量的名字,sig为成员函数或成员变量的签名信息。

2.使用jfieldID和jmethodID

NativeType Call<type>Method(JNIEnv *env, jobject obj, jmethod methodID, ...);
其中type对应Java的返回类型如CallIntMethod,对static函数:CallStatic<type>Mothod。
NativeType Get<type>Field(JNIEnv *env, jobject obj, jfield fieldID, NativeType value);

常用的Get/Set函数:
GetObjectField()  SetObjectField()
GetBooleanField()  SetBooleanField()
GetByteField()  SetByteField()
GetCharField()  SetCharField()
GetShortField()  SetShortField()
GetIntField()  SetIntField()
GetLongField()  SetLongField()
GetFloatField()  SetFloadField()
GetDoubleField()  SetDoubleField()

八.jstring介绍

获取jstring对象
NewString(JNIEnv * env, const jchar *unicodeChar, jsize len);
NewStringUTF(JNIEnv * env, const jchar *unicodeChar, jsize len);

Native字符串
GetStringChars(...);
GetStringUTFChars(...);

释放资源
ReleaseStringChars(...)
ReleaseStringUTFChars(...)

九.JNI类型签名介绍

1.动态注册

static JNINativeMethod getMethods[] = {
{
"methodName",
"(Ljava/lang/String;)I",
(void *) native_methodName
},
...
}
签名信息格式:
(参数1 类型标识  参数2 类型标识 ...)返回值类型标识。
当参数类型是引用类型时,其格式是“L包名”,其包名中的“.”换成“/”。


类型标识                             Java类型
Z                                          boolean
C                                          char
S                                          short
I                                            int
J                                           long
B                                           byte                                    
F                                           float
D                                           double
L/java/lang/String                  String
[I                                             int[]
[L/java/lang/object                  object[]

javap:工具生成函数和变量的签名信息
javap -s -p xxx
xxx为编译后class文件,s表示输出的内部数据类型信息,p表示打印所有函数和成员的签名信息默认为public类型。

十。垃圾回收

1.LocalReference:本地引用,非全局引用对象都是LocalReference。
2.Gloabal Reference:全局引用,这种对象不主动释放,永远不会被垃圾回收。NewGlobalRef()、ReleaseGlobalRef()来产生和解除引用
3.Weak Global Reference :弱全局引用,在引用过程中可能被垃圾回收。调用JNIEnv的IsSameObject判断它是否被回收。NewWeakGlobalRef()、ReleaseWeakGlobalRef()来产生和解除引用

十一.JNI异常处理

1.ExceptionOccured函数,用来判断是否发生异常。
2.ExceptionClear函数,用来清理当前JNI层中发生的异常。
3.ThrowNew函数,用来向Java抛出异常。

JNI编译成.so

1.下载NDK。
2.将NDK路径配置到Windows(电脑path)与JDK配置相同。
3.CMD命令到JNI存放目录。
4.输入ndk-build 生成.so。
5.JNI对应的libs存放生成的.so。

上一篇 下一篇

猜你喜欢

热点阅读