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");
}
}
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
yGetLongField
para almacenar la referencia del objeto de C++, pero también puede almacenar eljlong
puntero de objeto de Java como se discutió en otras respuestas. - En mi código final, implementé el
JavaObject
clase como unParcelable
para pasar mi clase a múltiples actividades usandoIntent
con extras.