这个问题和this one很像
这是我在 C++ 上保持对象活动以便从多个 JNI 调用中引用它们的解决方案:
Java
在 Java 方面,我正在创建一个带有 long 指针的类,以保留对 C++ 对象的引用。将 C++ 方法包装在 Java 类中,允许我们在多个活动中使用 C++ 方法。请注意,我在构造函数上创建了 C++ 对象,并在清理时删除了该对象。这对于防止内存泄漏非常重要:
public class JavaClass {
// Pointer (using long to account for 64-bit OS)
private long objPtr = 0;
// Create C++ object
public JavaClass() {
createCppObject();
}
// Delete C++ object on cleanup
public void cleanup() {
deleteCppObject();
this.objPtr = 0;
}
// Native methods
public native void createCppObject();
public native void workOnCppObject();
public native void deleteCppObject();
// Load C++ shared library
static {
System.loadLibrary("CppLib");
}
}
C++
在 C++ 方面,我定义了创建、修改和删除对象的函数。值得一提的是,我们必须使用new 和delete 将对象存储在HEAP 内存中,以使其在Java 类实例的整个生命周期中保持活动状态。我还将指向CppObject 的指针直接存储在JavaClass 中,使用getFieldId、SetLongField 和GetLongField:
// Get pointer field straight from `JavaClass`
jfieldID getPtrFieldId(JNIEnv * env, jobject obj)
{
static jfieldID ptrFieldId = 0;
if (!ptrFieldId)
{
jclass c = env->GetObjectClass(obj);
ptrFieldId = env->GetFieldID(c, "objPtr", "J");
env->DeleteLocalRef(c);
}
return ptrFieldId;
}
// Methods to create, modify, and delete Cpp object
extern "C" {
void Java_com_test_jnitest_JavaClass_createCppObject(JNIEnv *env, jobject obj) {
env->SetLongField(obj, getPtrFieldId(env, obj), (jlong) new CppObject);
}
void Java_com_test_jnitest_JavaClass_workOnCppObject(JNIEnv *env, jobject obj) {
CppObject* cppObj = (CppObject*) env->GetLongField(obj, getPtrFieldId(env, obj));
// Write your code to work on CppObject here
}
void Java_com_test_jnitest_JavaClass_deleteCppObject(JNIEnv *env, jobject obj) {
CppObject* cppObj = (CppObject*) env->GetLongField(obj, getPtrFieldId(env, obj));
delete cppObj;
}
}
注意事项:
- 与 Java 不同,C++ 没有垃圾回收,并且对象将驻留在 HEAP 内存中,直到您使用
delete。
- 我使用
GetFieldID、SetLongField 和GetLongField 来存储来自C++ 的对象引用,但您也可以存储来自Java 的jlong 对象指针,如其他答案所述。
- 在我的最终代码中,我将
JavaObject 类实现为 Parcelable,以便使用带有附加功能的 Intent 将我的类传递给多个活动。