JNI心得 - (五)多线程回调Java的处理方式

在日常jni开发中或多或少会用到多线程,前面提到过jnienv只对当前线程有效,在其他线程中是没有用的。这就成为了多线程编程的阻碍,接下来就去研究一下多线程环境下如何使用jnienv的。

首先还是先创建一个支持C++的androidstudio 项目,由于新创建的线程没有JNIEnv 环境,所以在创建线程之前要准备好创建JNIEnv的环境。虽然JNIEnv 是线程私有的,但是JavaVm 确实全局的,而且我们还可以从JavaVm中获当前线程的JniEnv,所以首先要缓存一个全局的JavaVm

JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    javaVM = vm;
    return JNI_VERSION_1_6;
}

JNI_OnLoad  的函数是在加载so的时候回调的,所以在这里缓存全局的JavaVM是最合适的,接下来就是创建一个线程,创建线程的函数

int pthread_create(pthread_t* __pthread_ptr, pthread_attr_t const* __attr, void* (*__start_routine)(void*), void*);

用法很简单,直接 上代码

    pthread_t t;
    pthread_create(&t, NULL, callBackFn, NULL);

这里的callBackFn 就是将要在新线程里运行的函数


void *callBackFn(void *arg) {


    int tag = 0;
    while (true) {

        JNIEnv *jniEnv;
        int res = javaVM->GetEnv((void **) &jniEnv, JNI_VERSION_1_6);

        if (res < JNI_OK) {

            int res = javaVM->AttachCurrentThread(&jniEnv, nullptr);

            if (res != JNI_OK) {

                break;
            }
        }

        jclass jclass1 = jniEnv->GetObjectClass(object);
        jmethodID jmethodID1 = jniEnv->GetMethodID(jclass1, "onCallBack", "(Ljava/lang/String;)V");

        int i = 0;
        char c[1];
        sprintf(c, "%d", tag++);

        jstring jtag = jniEnv->NewStringUTF(c);
        jniEnv->CallVoidMethod(object, jmethodID1, jtag);

        jniEnv->DeleteLocalRef(jtag);
        jniEnv->DeleteLocalRef(jclass1);

        sleep(1);

    }

    javaVM->DetachCurrentThread();

    return NULL;

}

通过以上几步,就可以在新线程内获取JniEnv环境了。

下载代码

你可能感兴趣的:(JNI心得)