如何在单独的线程中从c++调用对象上的Java函数



好吧,我不能让这个工作。我在Android上使用JNI来启动大量的c++代码。我想发送一个字符串回主活动,所以我可以在屏幕上显示它,但我一直卡住。经过大量的工作后,我确实发现我需要首先附加当前线程,因为我的jvm指针无效。但是现在我不知道如何从这个新线程中使用我的MainActivity的工作对象。

开始c++代码,我这样做:

extern "C" JNIEXPORT jstring JNICALL
Java_com_myname_mydetails_myfunction_MainActivity_startItUp(
JNIEnv* env,
_jobject *jobjecte /* this */) {
//trying to store the JVM
jint err = env->GetJavaVM(&jvm);
//start the cameras up starting with camera 1
startThings(jvm, jobjecte, env);
//return a the Starting Cameras String for the java UI
return env->NewStringUTF(hello.c_str());
}

我用这个函数

将这些点传递给c++对象
void setJVM( JavaVM *_jvm, _jobject *_mainActivity, JNIEnv* _env){
jvm = _jvm;
mainActivity = _mainActivity;
env = _env;
}

现在在我的c++线程中。

void myclass::mymethod(int64_t _profile){
JNIEnv *env = NULL;
JavaVMAttachArgs args;
args.version = JNI_VERSION_1_6; // choose your JNI version
args.name = NULL; // you might want to give the java thread a name
args.group = NULL; // you might want to assign the java thread to a ThreadGroup
jvm->AttachCurrentThread(&env, &args);
jclass clazz = env->GetObjectClass(mainActivity);

当我从线程调用mymethod时,我得到:JNI检测到应用程序中的错误:使用无效的工作对象。所以好吧,公平地说,我猜,如果JVM指针在线程之间不相同,那么jobobject指针也不相同。但是,我如何得到指针到我的主活动对象调用我的java函数?

为了在本机代码中存储Java对象,您需要存储对它的global引用。要将local引用转换为全局引用,需要调用env->NewGlobalRef(local_object);

这将返回一个全局对象引用,现在您可以在任何地方使用它。稍后,当您完成使用对象时,您需要使用env->DeleteGlobalRef(global_object);对其进行清理。如果不这样做,对象将永远不会被JVM垃圾收集。

同样,做env->DeleteLocalRef(local_object)也是一个好习惯。例如,如果你这样做:

void execute_some_code() {
jclass local_class = env->FindClass(....);
jobject local_object = env->CallObjectMethod(....);
_my_object = env->NewGlobalRef(local_object);
// MUST cleanup local references since these references were not given to you by the JVM, but rather created by you in native code.
env->DeleteLocalRef(local_object);
env->DeleteLocalRef(local_class);
}

现在要解决这个问题,如上所述将对象存储为global引用。然后您可以在任何Attached线程上访问它。不要忘记在线程死亡之前将其detach(否则,如果它将始终运行,则将其附加为守护进程)。

void startThings(JVM* jvm, jobject* jobject, JNIEnv* env) {
setJVM(jvm, env->NewGlobalRef(jobject), env);
// Possible other code
std::thread([]{
JNIEnv* local_env = NULL;
JavaVMAttachArgs args = {....};

int err = _jvm->AttachCurrentThread(&local_env, &args);
if (err != JNI_OK) {
return;
}
// Do stuff with _mainActivity
// Some time later in your application:
local_env->DeleteGlobalRef(_mainActivity);
_jvm->DetachCurrentThread();
}).detach();
}
extern "C" JNIEXPORT jstring JNICALL
Java_com_myname_mydetails_myfunction_MainActivity_startItUp(
JNIEnv* env,
_jobject *jobject /* this */) {
jint err = env->GetJavaVM(&jvm);

startThings(jvm, jobject, env);
// Optional here but a good habit to know how it works
env->DeleteLocalRef(jobject);
return env->NewStringUTF(hello.c_str());
}

如果你正在使用c++ 11,你可以使用std::unique_ptr和一个自定义删除器来处理所有的内存管理,比如删除全局引用:)

最新更新