簡體   English   中英

Android NDK,保存實時C ++對象

[英]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部分直接設置它SetLongFieldGetLongField方法:這允許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 ++方面,我定義了創建,修改和刪除對象的函數。 值得一提的是,我們必須使用newdelete將對象存儲在HEAP內存中,以使其在Java類實例的整個生命周期中保持活動狀態。 我還使用getFieldIdSetLongFieldGetLongField直接在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;
    } 

}

筆記:

  • 與Java不同,C ++沒有垃圾收集,並且對象將存在於HEAP內存中,直到您使用delete
  • 我正在使用GetFieldIDSetLongFieldGetLongField來存儲來自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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM