问题:
我要用ndk编译c++的代码,其中包含了多线程,主线程和回调线程。
在主线程中使用env->GetJavaVM(&g_jvm);得到了全局的vm,
在回调线程中我首先得到了env:
JNIEnv* env = NULL;
g_jvm->AttachCurrentThread(&env, NULL);
然后利用
jclass cls = env->FindClass("vc/db/DataSearchService");
(其中vc/db是包名,DataSearchService是自定义的类名)
在主线程中调用 env->FindClass("vc/db/DataSearchService");是没有问题的
解决方案:
1.在主线程调用 jclass cls = env->FindClass("vc/db/DataSearchService"); 然后用NewGlobalRef
为这个cls申请全局引用,否则这只是个局部引用,跨线程仍然挂。
<结构体>
typedef struct java_callback {
int code;
jobject obj;
jobject cls;//回调需要的java bean
void *response;
} java_callback;
java_callback javaCallback;
<主线程调用>
JNIEXPORT void JNICALL
Java_com_xxx_xxx_testCallback(JNIEnv *env, jobject thiz, jobject query_order_listener) {
javaCallback.obj = (env)->NewGlobalRef(query_order_listener);
jclass cls= env->FindClass("com/xxx/xxx/QueryOrderBean");
javaCallback.cls = env->NewGlobalRef(cls);
}
<子线程中调用:>
/**
* 在此处跑在子线程中,并回调到java层
*/
void *callbackThreadHandler(void *p) {
if (p == NULL) {
logE("callbackThreadHandler>>>p is NULL");
pthread_exit(&callbackThread);
}
JNIEnv *env;
//获取当前native线程是否有没有被附加到jvm环境中
int getEnvStat = g_VM->GetEnv((void **) &env, JNI_VERSION_1_6);
if (getEnvStat == JNI_EDETACHED) {
//如果没有,主动附加到jvm环境中,获取到env
if (g_VM->AttachCurrentThread(&env, NULL) != 0) {
pthread_exit(&callbackThread);
}
}
//强转回来
auto jcallback = (java_callback *) p;
//通过强转后的jcallback 获取到要回调的类
jclass javaClass = env->GetObjectClass(jcallback->obj);
if (javaClass == 0) {
logE("Unable to find class");
g_VM->DetachCurrentThread();
pthread_exit(&callbackThread);
}
//获取要回调的方法ID 参数1:类名, 参数2:方法名, 参数3:方法名的签名
jmethodID javaCallbackId = env->GetMethodID(javaClass, "onQueryOrder",
"(Lcom/xxx/xxx/QueryOrderBean;)V");
if (javaCallbackId == NULL) {
logE("Unable to find method: onFaceDetect");
pthread_exit(&callbackThread);
}
//找到对象的Java类
auto queryOrderClass = (jclass) jcallback->cls;
// 获取类的构造函数,记住这里是调用无参的构造函数
jmethodID id = env->GetMethodID(queryOrderClass, "<init>", "()V");
// 创建一个新的对象
jobject queryOrderBean = env->NewObject(queryOrderClass, id);
//对应的java属性
jfieldID time = env->GetFieldID(queryOrderClass, "time", "Ljava/lang/String;");
//属性赋值,queryOrderBean
env->SetObjectField(queryOrderBean, time, env->NewStringUTF(response2021->time));
//执行回调
env->CallVoidMethod(jcallback->obj, javaCallbackId, queryOrderBean);
env->DeleteLocalRef(queryOrderBean);
}
class QueryOrderBean {
val time: String = ""
}
网友评论