一.JNI概论
二.库命名方式
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;
五.数据类型
六.JNIEnv介绍
JNI是一个与线程相关的代表JNI环境的结构体。线程相关结构指向JNI函数指针数组,这个数组中存放了大量的JNI函数指针,这些指针指向了详细的JNI函数。
注:调用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。