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
传递给所有需要它的方法,您还可以使用 SetLongField
和 GetLongField
方法直接从 NDK 部分获取并设置它:这允许仅从代码的 NDK 部分管理 Java ptr
变量,我觉得这更安全、更容易管理。
我开始谈话有点晚了,但由于我找不到彻底回答这个问题的 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
将对象存储在堆内存中,以使其在 Java 类实例的整个生命周期中保持活动状态。我还使用 getFieldId
、SetLongField
和 GetLongField
将指针CppObject
存储在JavaClass
中
// 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++ 没有垃圾回收,对象将存在于堆内存中,直到您使用
delete
。 - 我正在使用
GetFieldID
、SetLongField
和GetLongField
来存储来自C++的对象引用,但您也可以存储来自 Java 的jlong
对象指针,如其他答案中所述。 - 在我的最终代码中,我将
JavaObject
类实现为Parcelable
,以便使用带有附加内容的Intent
将我的类传递给多个活动。
来实例化你的原生对象,只要你持有对它的引用,它就不会被销毁(丢失引用使其有资格进行垃圾回收,这将在 Java 引用完成时调用 C++ Object 实例上的析构函数)。
但是,如果本机代码和 Java 代码之间的交互很小,则使用 SWIG 可能过于 OTT。
- Constexpr替代了新的放置方式,可以让内存中的对象保持未初始化状态
- 从数据库实时显示QT c++中的数据
- 我不断收到 [错误] ID 返回 1 退出状态错误,但看不到问题所在
- OSX MetalKit CVMetalTextureCacheCreateTextureFromImage失败,状态:
- std::future_error:无关联状态
- 如何避免LED在循环状态变化中闪烁?
- 在 Windows 8/10 技术中完全实时的屏幕捕获,没有延迟
- boost 是否有按特殊类型值编码状态"compact optional"?
- 有没有办法使用 c++ 实时阅读文本?
- 在本地网络中通过OpenCV(C++)实时流式传输图像
- 为什么系统函数总是在C++中返回已转移的退出状态?
- C++ 中的编译错误:未定义对"主"的引用 collect2:错误:ld 返回 1 个退出状态
- 将相机数据从服务器实时流式传输到客户端
- 当可输入框在窗口中处于活动状态时获得通知的任何方法
- 检查两个节点在子节点上是否具有相同状态的更优雅的方法
- 将有状态的 lambda 传递到 C 样式函数中,而无需上下文参数
- 在 nullptr 上调用无状态类的非静态成员函数是否合法?
- 编译问题:在函数"_start"中:未定义对"主"的引用 collect2:错误:ld 返回 1 个退出状态
- 将实时(非静态)放在qt(c ++)上
- Android NDK,保持C++对象的实时状态