gpt4 book ai didi

android - 使用 JNI 调用更改 Activity 或使用 Openfeint 导致 App-Crash

转载 作者:塔克拉玛干 更新时间:2023-11-02 22:22:41 27 4
gpt4 key购买 nike

当我想通过 C++ 代码中的 JNI 调用更改我的 Android 应用程序的 Activity 时,我遇到了一个大问题。该应用程序使用 cocos2d-x 进行渲染。具体情况是我想用这个很小的函数用Java打开OpenFeint-Dashboard:

void launchOpenFeintDashboard() {
Dashboard.open();
}

然后使用简单的 JNI 调用从 C++ 调用此函数:

void
OFWrapper::launchDashboard() {
// init openfeint
CCLog("CPP Init OpenFeint Dashboard");

CCDirector::sharedDirector()->pause();

jmethodID javamethod = JNIManager::env()->GetMethodID(JNIManager::mainActivity(), "launchOpenFeintDashboard", "()V");
if (javamethod == 0)
return;
JNIManager::env()->CallVoidMethod( JNIManager::mainActivityObj(), javamethod );

CCLog("CPP Init OpenFeint Dashboard done");
}

JNIManager 类的实现也非常简单和基本:

#include "JNIManager.h"
#include <cstdlib>

static JNIEnv* sJavaEnvironment = NULL;
static jobject sMainActivityObject = NULL;
static jclass sMainActivity = NULL;


extern "C" {
JNIEXPORT void JNICALL Java_net_plazz_mainzelapp_mainzelapp_sendJavaEnvironment(JNIEnv* env, jobject obj);
};

// this function is called from JAVA at startup to get the env
JNIEXPORT void JNICALL Java_net_plazz_mainzelapp_mainzelapp_sendJavaEnvironment(JNIEnv* env, jobject obj)
{
sJavaEnvironment = env;
sMainActivityObject = obj;
sMainActivity = JNIManager::env()->GetObjectClass(obj);
}



JNIEnv*
JNIManager::env()
{
return sJavaEnvironment;
}

jobject
JNIManager::mainActivityObj()
{
return sMainActivityObject;
}

jclass
JNIManager::mainActivity()
{
return sMainActivity;
}

在我看来,cocos2d-x 在使用 JNI 调用更改 Activity 时存在一些关键问题,因为在将 Activity 更改为任何自己的 Activity 时我也会遇到 App-Crash。

但是,当我简单地使用 OpenFeint 通过 JNI 调用更新成就时,我会遇到应用程序崩溃,这与更改 Activity 时类似:

void updateAchievementProgress( final String achievementIdStr, final String progressStr ) {
Log.v("CALLBACK", "updateAchievementProgress (tid:" + Thread.currentThread().getId() + ")");

float x = Float.valueOf(progressStr).floatValue();
final Achievement a = new Achievement(achievementIdStr);
a.updateProgression(x, new Achievement.UpdateProgressionCB() {
@Override
public void onSuccess(boolean b) {
Log.e("In Achievement", "UpdateProgression");
a.notifyAll();
}

@Override
public void onFailure(String exceptionMessage) {
Log.e("In Achievement", "Unlock failed");
a.notifyAll();
}
});
Log.v("CALLBACK", "updateAchievementProgress done (tid:" + Thread.currentThread().getId() + ")");
}

这让我想到了我要说的一点,Android 或 Cocos2d-x 在异步执行某些操作(更新成就)或结合使用 NDK 更改 Activity (我使用 NDKr7,但相同在 NDKr5 上)。

您还应该知道,我已经在 J​​ava 中定义了一些其他函数,这些函数通过 JNI 调用进行调用并且可以正常工作!

也许我做错了什么,有人可以给我一些关于这个或如何更改 Activity 的工作示例代码的建议。可能是 Cocos2d-x 的问题。

谢谢。

最佳答案

我不知道 Dalvik 的实现,但 @Goz 是对的:JNIEnv 指针的范围只是在您调用的 JNI 函数的持续时间内。如果你想从 native 代码回调到 Java,你不能只保存上一次调用的 JNIEnv,因为那个可能不再有效(因此 appcrashes)。如果您只有一个线程来处理所有事情,那么它就可以工作。

您需要做的(如果您有多个线程),是在每次回调时获取一个有效的 JNIEnv 指针。在初始化函数中,您保存一个指向当前运行的虚拟机的指针:

JavaVM *jvm;
env->GetJavaVM(&jvm);

然后您可以使用此对正在运行的虚拟机的引用,通过调用以下方法获取有效的 JNIEnv 指针:

JNIEnv *env;
jvm->AttachCurrentThread((void **)&env, NULL);

然后你就可以使用环境了,完成后别忘了调用

jvm->DetachCurrentThread();

附加/分离将导致 Java 向 Thread 对象注册调用者(可以是 native 线程),这允许它被视为 Java 线程。

免责声明:至少,这是您在桌面 Java 中执行此操作的方式。不知道 Dalvik 实现,但从外观上看,他们只是复制了该技术。

关于android - 使用 JNI 调用更改 Activity 或使用 Openfeint 导致 App-Crash,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9615899/

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