Android NDK, manteniendo activos los objetos de C++

Android NDK, manteniendo activos los objetos de C++

Sí, puede hacer exactamente lo mismo que hizo en C#.

Para crear su nuevo objeto C++:

jlong
Java_package_name_new(JNIEnv *, jobject) {
  return (long)(new CPP_Object()); 
}

Puede almacenar el valor de retorno de este método en un Java ptr y pásela a todos los métodos del NDK que la necesiten:

void
Java_package_name_doSomething(JNIEnv *, jobject, jlong ptr) {
  CPP_Object *obj = (CPP_Object *)ptr;
  // do whatever you want with the object
}

Y finalmente elimínelo con algo como:

void
Java_package_name_delete(JNIEnv *, jobject, jlong ptr) {
  delete (CPP_Object *)(ptr);
}

En lugar de pasar ptr a todos los métodos que lo necesitan, también puede obtenerlo y configurarlo directamente desde la parte NDK usando el SetLongField y GetLongField métodos:esto permite que Java ptr variable que se administrará solo desde la parte NDK del código, que me parece más segura y fácil de administrar.


Llegué un poco tarde a la conversación, pero como no pude encontrar una publicación SO que responda esta pregunta a fondo, publicaré mi solución.

Java

En el lado de Java, estoy creando una clase con un long puntero para mantener una referencia al objeto C++. Envolver los métodos de C++ en una clase de Java nos permite usar los métodos de C++ en múltiples actividades. Tenga en cuenta que estoy creando el objeto C++ en el constructor y estoy eliminando el objeto en la limpieza. Esto es muy importante para evitar pérdidas de memoria:

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++

En el lado de C++, estoy definiendo funciones para crear, modificar y eliminar el objeto. Es importante mencionar que tenemos que usar new y delete para almacenar el objeto en la memoria HEAP para mantenerlo activo durante todo el ciclo de vida de las instancias de la clase Java. También estoy almacenando el puntero a CppObject directamente en el JavaClass , usando getFieldId , SetLongField y 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;
    } 

}

NOTAS:

  • A diferencia de Java, C++ no tiene recolección de basura, y el objeto vivirá en la memoria HEAP, hasta que use delete .
  • Estoy usando GetFieldID , SetLongField y GetLongField para almacenar la referencia del objeto de C++, pero también puede almacenar el jlong puntero de objeto de Java como se discutió en otras respuestas.
  • En mi código final, implementé el JavaObject clase como un Parcelable para pasar mi clase a múltiples actividades usando Intent con extras.