[英]Android NDK, keeping live C++ objects
我有一個以下問題。 我想編寫一個Android應用程序,它使用我的舊C ++類。 我必須在整個應用程序生命周期中保持C ++對象的存活。
我在C#中編寫了一個類似的應用程序,並通過將指向C ++的指針傳遞給C#並使用IntPtr將其存儲在那里來解決問題。 然后,當我想在該對象上調用一個方法時,我只是將該指針再次傳遞給C ++,轉換為類指針並在其上調用一個方法。
如何在Java和Android NDK中實現類似的結果? Java是否支持存儲指針?
是的,你可以做的與你在C#中做的完全相同。
要創建新的C ++對象:
jlong
Java_package_name_new(JNIEnv *, jobject) {
return (long)(new CPP_Object());
}
您可以將此方法的返回值存儲在Java ptr
變量中,並將其傳遞給需要它的所有NDK方法:
void
Java_package_name_doSomething(JNIEnv *, jobject, jlong ptr) {
CPP_Object *obj = (CPP_Object *)ptr;
// do whatever you want with the object
}
最后用以下內容刪除它:
void
Java_package_name_delete(JNIEnv *, jobject, jlong ptr) {
delete (CPP_Object *)(ptr);
}
而不是傳遞的ptr
到需要它的所有方法,你還可以得到它,並使用從NDK部分直接設置它SetLongField
和GetLongField
方法:這允許Java ptr
變量只從代碼的NDK的一部分來管理,這我覺得更安全,更容易管理。
我的談話時間有點遲了,但由於我找不到能夠徹底回答這個問題的SO帖子,我會發布我的解決方案。
Java的
在Java方面,我創建了一個帶有long
指針的類來保持對C ++對象的引用。 在Java類中包裝C ++方法允許我們在多個活動中使用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類實例的整個生命周期中保持活動狀態。 我還使用getFieldId
, SetLongField
和GetLongField
直接在JavaClass
存儲指向CppObject
的指針:
// 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;
}
}
筆記:
delete
。 GetFieldID
, SetLongField
和GetLongField
來存儲來自C ++的對象引用,但您也可以存儲來自Java的jlong
對象指針,如其他答案中所討論的。 JavaObject
類實現為Parcelable
,以便使用Intent
和extras將我的類傳遞給多個活動。 你也可以使用SWIG封裝你的C ++代碼,你可以通過在Java中構建它來實例化你的本機Object,只要你持有它的引用,它就不會被破壞(丟失引用使它有資格進行垃圾收集)在Java引用完成時調用C ++ Object實例上的析構函數)。
但是,如果本機代碼和Java代碼之間的交互很少,那么使用SWIG可能太OTT了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.