[019]JNI基础

前言

如果要对android系统有一个深入的理解,Native层C/C++是代码是必看的,Binder的底层实现,Input子系统,Looper采用都是JAVA和C++混合的方式设计的模块。要看懂这些Native的代码首先要了解的是JNI

JNI是什么

JNI是Java Native Interface的缩写,翻译就是JAVA本地接口,其实就是JAVA调用C/C++的一套接口

为什么使用JNI?

a.效率上C&C++比Java高,
b.C&C++的反编译比Java难度高
c.如果之前用C&C++开发的模块,可以通过JNI来复用

但是一旦使用JNI,就会让Java失去跨平台功能,需要在不同的系统平台下编译本地语言

JNI基本使用-静态注册

JNI基本使用-动态注册

[019]JNI基础_第1张图片

动态注册对比静态注册

1.静态注册

编写不方便,JNI 方法名字必须遵循规则且名字很长
程序运行效率低,因为初次调用native函数时需要根据根据函数名在JNI层中搜索对应的本地函数,然后建立对应关系,这个过程比较耗时

2.动态注册

流程更加清晰可控
效率更高

JNI基本使用-将Native层的类和Java的类绑定

[019]JNI基础_第2张图片

JNI基本使用-拿到JAVA层的保存的Native对象并调用Native层的方法

extern "C" JNIEXPORT jint JNICALL
Java_com_kobe_startjni_MainActivity_getValue(
        JNIEnv *env,
        jobject object) {
    jclass jclazz = env->FindClass("com/kobe/startjni/MainActivity");
    jfieldID jfield = env->GetFieldID(jclazz, "nativeMainActivity", "J");
    //将Java层的nativeMainActivity的值强制转化成Native层的NativeMainActivity的指针
    NativeMainActivity *mainActivity = (NativeMainActivity *) env->GetLongField(object, jfield);
    return mainActivity->getValue();
}

JNI基本使用-Native层的对象调用Java层的对象的方法

extern "C" JNIEXPORT void JNICALL
Java_com_kobe_startjni_MainActivity_startCallBack(
        JNIEnv *env,
        jobject /* this */ object) {
    jclass jclazz = env->FindClass("com/kobe/startjni/MainActivity");
    jfieldID jfield = env->GetFieldID(jclazz, "nativeMainActivity", "J");
    jmethodID jmethod = env->GetMethodID(jclazz, "callBack", "()V");
    env->CallVoidMethod(mainActivity->mainActivity, jmethod);
}

JNI基本使用-在Native中创建Java对象

extern "C" JNIEXPORT void JNICALL
Java_com_kobe_startjni_MainActivity_createJavaObject(
        JNIEnv *env,
        jobject /* this */ object) {
    jclass jclazz1 = env->FindClass("com/kobe/startjni/MainActivity");
    jclass jclazz2 = env->FindClass("com/kobe/startjni/MyClass");
    jfieldID jfield = env->GetFieldID(jclazz1, "myClass", "Ljava/lang/Object;");
    //找到MyClass的构造函数
    jmethodID  init = env->GetMethodID(jclazz2, "", "()V");
    //在native层中创建java层的MyClass对象
    jobject myclass = env->NewObject(jclazz2, init);
    //将MyClass对象赋值到java层中MainActivity的属性myClass
    env->SetObjectField(object, jfield, myclass);
}

总结

1.Java层调用Native层的方法,只能通过动态注册或者静态注册的JNI接口
2.Java层可以保存Native层对象的指针long,Native层可以保存Java层的对象jobject(NewGlobalRef),一定要注意内存泄露
3.Native层可以通过类似反射的方式,设置Java层对象的属性或者回调Java层对象的方法
4.Native层可以创建Java层的对象,但是Java层无法直接创建Native层的对象,需要通过JNI的接口。

你可能感兴趣的:([019]JNI基础)