【发布时间】:2019-11-21 17:05:55
【问题描述】:
我正在使用 Android NDK,需要访问资产。资产访问的要求似乎是获取 AssetManager 引用。
查看 NDK 样本 (https://github.com/android/ndk-samples),模式似乎是:
- 当直接从 JavaVM 调用时,
JNIEnv*与一些jobject一起被传递到 func - 使用这些获取
AAssetManager*,然后使用它打开资产
这似乎很简单,但在我的情况下,函数是从 Unity 调用的,所以我无法访问 JNIEnv* 或 jobject。获得JNIEnv* 似乎很容易,因为我可以使用JNI_OnLoad 来访问JavaVM*,然后使用它通过vm->GetEnv 获得JNIEnv*。我的问题是:
1) 我的理解是,Android 应用程序只能有一个 Java VM 实例。我可以安全地将JavaVM* 传递给JNI_OnLoad 并将其保存以用于其他函数调用吗?
2) JNIEnv* 呢?我可以在JNI_OnLoad 期间抓取一次并保存它,还是每次我需要在函数中使用资产时抓取一个新的? JNIEnv* 是我需要明确释放的东西吗? (即JNIEnv* 的生命周期/所有权情况如何?)
3) AAssetManager_fromJava 还需要 jobject 和文档 (https://developer.android.com/ndk/reference/group/asset#group___asset_1gadfd6537af41577735bcaee52120127f4) 说:“请注意,调用者负责获取并持有对作业对象的 VM 引用,以防止其在本机对象被垃圾收集时被垃圾回收。正在使用。”。我似乎有一些示例只是传入一个空(本机)字符串,例如AAssetManager_fromJava(env, ""); - 可以吗?我只会在该调用的整个生命周期内使用 AssetManager,并且每次都可以获得一个新的。 (同样,AAssetManager* 是我需要管理的资源,还是我只是引用了其他地方拥有的东西?文档似乎暗示了后者。)
4) 鉴于以上所有情况,我可能会这样做:
JavaVM* g_vm;
JNIEnv* g_env;
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
g_vm = vm;
g_vm->GetEnv((void **)&g_env, JNI_VERSION_1_6); // TODO: error checking
return JNI_VERSION_1_6;
}
void do_asset_stuff() {
AAssetManager* mgr = AAssetManager_fromJava(g_env, "");
// do stuff...
}
这样合理吗?没有内存/资源泄漏问题?多线程有什么问题吗?
谢谢!
编辑:JNIEnv* 似乎有一些线程注意事项。见:Unable to get JNIEnv* value in arbitrary context
【问题讨论】:
标签: android unity3d android-ndk java-native-interface