在日常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环境了。