Intereting Posts
Как установить цвет текста в приложении Android для всего текста? Уведомление от IntentService – исключение NullPointerException при получении контекста Почему программа cordova.exec () работает в моем приложении Android PhoneGap (1.7) до «deviceready»? Пользовательский дочерний класс приложения в Mono для Android Есть ли способ добавить параметр запроса к каждому запросу с помощью Retrofit 2? Разница между кликом и нажатием на Android Индикатор обновления SweepRefreshLayout Android не отображается Служба GeoCoder недоступна Добавление программы LinearLayout программно в Android не работает Как я могу исправить все, что вызывает это, чтобы нагрузить мой logcat: I / System.out: (HTTPLog) -Static: isSBSettingEnabled false Как повернуть растровое изображение на 90 градусов Как я могу получить окно активности стиля диалога, чтобы заполнить экран? Как активировать активность в диалоговом окне «Выбрать файл»? Как получить все имена таблиц в базе данных android sqlite? Переопределить экран входящих вызовов?

Android NDK, поддерживающий живые объекты C ++

У меня есть следующая проблема. Я хочу написать приложение для Android, которое использует мои устаревшие классы C ++. Я должен сохранить объект C ++ в течение всего срока службы приложения.

Я написал аналогичное приложение в C # и решил проблему, передав указатель на C ++-класс на C # и сохранив его там, используя IntPtr. Затем, когда я хотел вызвать метод для этого объекта, я просто передал этот указатель снова на C ++, преобразован в указатель класса и вызвал метод на нем.

Как добиться такого же результата в Java и Android NDK? Поддерживает ли Java поддержку указателей?

Solutions Collecting From Web of "Android NDK, поддерживающий живые объекты C ++"

Да, вы можете сделать то же самое, что и на 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 : это позволяет управлять переменной ptr Java только из части кода NDK кода, которая Я нахожу себя более безопасным и простым в управлении.

Вы также можете обернуть свой код на C ++ с помощью SWIG , где вы создаете экземпляр собственного объекта, создавая его на Java, и до тех пор, пока вы держите ссылку на него, он не уничтожается (потеря ссылки делает его пригодным для сбора мусора, который будет Вызовите деструктор на экземпляр объекта C ++, когда ссылка Java завершена).

Однако, если взаимодействие между собственным кодом и кодом Java минимально, использование SWIG может быть слишком OTT.

Я немного опоздал на разговор, но, поскольку я не мог найти сообщение SO, которое полностью отвечает на этот вопрос, я опубликую свое решение.

Ява

На стороне 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 ++, но вы также можете сохранить jlong объект jlong из Java, как описано в других ответах.
  • В моем конечном коде я реализовал класс JavaObject как Parcelable , чтобы передать мой класс нескольким действиям с использованием Intent с дополнительными функциями.