gpt4 book ai didi

android - 在插件中使用 AAssetManager_fromJava 不直接从 Java VM 调用(从 Unity 调用)

转载 作者:行者123 更新时间:2023-12-02 20:42:03 34 4
gpt4 key购买 nike

我正在使用 Android NDK 并且需要访问资源。 Assets 访问的一个要求似乎是获取 AssetManager 引用。

查看 NDK 示例 ( https://github.com/android/ndk-samples ),模式似乎是:

  • 直接从 JavaVM 调用时,JNIEnv* 会连同一些 jobject 一起传递到 func 中
  • 使用它们来获取 AAssetManager*,然后使用它来打开资源

这看起来很简单,但在我的例子中,这些函数是从 Unity 调用的,因此我无法访问 JNIEnv*jobject。获取 JNIEnv* 似乎很容易,因为我可以利用 JNI_OnLoad 来访问 JavaVM*,然后使用它来获取 JNIEnv* 通过vm->GetEnv。我对此的疑问是:

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 ) 指出:“请注意,调用者负责获取并保存对 jobject 的 VM 引用,以防止其被垃圾收集当 native 对象正在使用时。”。我看到一些例子只是简单地传入一个空( native )字符串,例如 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

最佳答案

逐条回答您的问题:

  1. 是的,可以有only one VM在安卓中。您可以存储此指针或使用 JNI_GetCreatedJavaVMs .

  2. JNIEnv 指针与创建它们的线程紧密耦合。在您的情况下,您首先必须 attach the thread to the VM using AttachCurrentThread 。这将为您填写一个 JNIEnv *。完成后,不要忘记 DetachCurrentThread

    另请注意有关 FindClass 的警告:您需要从主线程或通过在主线程中查找的类的类加载器查找类。

  3. 执行AAssetmanager_fromJava非常清楚:向其传递除了 AssetManager 对象之外的任何内容都是未定义的行为。 This answer显示了一种获取 Assets 管理器的方法,另一种可能是通过引用 AssetManager 对象来调用您自己的 JNI 函数。确保保留全局引用,以免被GC。

  4. 鉴于上述情况,它可能看起来更像这样:

JavaVM* g_vm;
jobject cached_assetmanager;

jint JNI_OnLoad(JavaVM* vm, void* reserved) {
g_vm = vm;
return JNI_VERSION_1_6;
}

void do_asset_stuff() {
JNIEnv *env;
JavaVMAttachArgs args = { JNI_VERSION_1_6, "my cool thread", NULL };
g_vm->AttachCurrentThread((void **)&env, &args);
AAssetManager* mgr = AAssetManager_fromJava(g_env, cached_assetmanager);
// do stuff...
}

// Assuming you call `com.shhhsecret.app.storeassetmanager(mgr)` somewhere.
void Java_com_shhhsecret_app_storeassetmanager(JNIEnv *env, jclass cls, jobject am) {
cached_assetmanager = env->NewGlobalRef(am);
}

关于android - 在插件中使用 AAssetManager_fromJava 不直接从 Java VM 调用(从 Unity 调用),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58980171/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com