C/C++语言基础 –> JNI编程 –> NDK编程 –> 音视频处理 –> 图像处理等等 ,从零到一 , 零基础学习NDK开发 。学习本专题 , 你需要具备一定的Android开发知识 C/C++基础, 知道如何创建一个Android工程 , 有一定的开发经验更佳 。

本篇主要讲解JNI的一些高级写法和线程,文章内容都非常简单。

JNI_OnLoad

上一章讲的JNI 编程详解
Java 要调用C++的方法,都要写一大长串比如:

extern "C"
JNIEXPORT void JNICALL
Java_com_jnimode1_MainActivity_updateGolbal(JNIEnv *env, jobject instance, jclass jclass1)

上述相当于静态注册,而JNI_OnLoad是动态注册,两者其实没什么区别,简化了方法名让人更容易理解。

简化后

void updateGolbal(jclass cls)

下面我们看一个例子就理解了,都有注释,so easy

JavaVM *_vm;

void dynamicTest() {
    LOGE("我是被动态注册的方法dynamicTest");
}

//JNIEnv *env, jobject instance 如果传参数这两个参数必须存在
jint dynamicTest2(JNIEnv *env, jobject instance, jint i) {
    LOGE("我是被动态注册的方法dynamicTest2");
    return i;
}

//静态的Jni native 方法数组
static const JNINativeMethod method[] = {
        //方法名    签名    本地方法
        {"dynamicJavaTest",  "()V",  (void *) dynamicTest},
        {"dynamicJavaTest2", "(I)I", (int *) dynamicTest2}
};

//类名
static const char *mClassName = "com/jnimode1/MainActivity";

//返回Jni 版本
int JNI_OnLoad(JavaVM *vm, void *r) {
    LOGE("JNI_OnLoad");
    _vm = vm;
    JNIEnv *env = 0;
    //获得JNIEnv 这里会返回一个值 小于0 代表失败
    jint res = vm->GetEnv((void **) (&env), JNI_VERSION_1_6);
    //判断返回结果
    if (res != JNI_OK) {
        return -1;
    }
    //根据类名找到类,注意有native的类不能被混淆
    jclass jcls = env->FindClass(mClassName);
    //动态注册  第一个参数 类  第二个参数 方法数组  第三个参数 注册多少个方法
    env->RegisterNatives(jcls, method, sizeof(method) / sizeof(JNINativeMethod));
    return JNI_VERSION_1_6;
}

Activity 中调用

public native void dynamicJavaTest();

    public native int dynamicJavaTest2(int i);

native线程调用Java

native调用java需要使用JNIEnv这个结构体,而JNIEnv是由Jvm传入与线程相关的变量。

但是可以通过JavaVM的AttachCurrentThread方法来获取到当前线程中的JNIEnv指针。

jobject _instance;

void *task(void *args){
     JNIEnv *env;

    //将本地当前线程附加到 jvm 并获得jnienv
    //成功则返回0
    jint res = _vm->AttachCurrentThread(&env,0);

    if (res != JNI_OK){
        return 0;
    }

    jclass jclass1 = env->GetObjectClass(_instance);

    jmethodID staticMethod = env->GetStaticMethodID(jclass1,"staticMothed","(I)V");

    env->CallStaticVoidMethod(jclass1,staticMethod,100);


    jmethodID  jmethodID1 = env->GetMethodID(jclass1,"instanceMothed","(Ljava/lang/String;)V");

    jstring jstring1 = env->NewStringUTF("我是C++");



    env->CallVoidMethod(_instance,jmethodID1,jstring1);

    env->DeleteLocalRef(jclass1);
    env->DeleteLocalRef(jstring1);
    env->DeleteGlobalRef(_instance);

    //分离
    _vm->DetachCurrentThread();

    return 0;

}

void nativeThread2(JNIEnv *env,jobject instace){
    _instance = env->NewGlobalRef(instace);//_instacne 设置为全局引用
    pthread_t pthread;
    pthread_create(&pthread,0,task,0);
}