什么是保存的JNIEnv的最佳途径* [英] What is the best way to save JNIEnv*

查看:871
本文介绍了什么是保存的JNIEnv的最佳途径*的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个JNI Android项目。在它实现了一个监听器类CPP文件,有回调X()。当x()函数被调用时,我想调用Java类另一个功能。然而,为了调用该Java函数,我需要访问的JNIEnv *。

I have an Android project with JNI. In the CPP file which implements a listener class, there is a callback x() . When x() function is called, I want to call another function in a java class. However, in order to invoke that java function, I need to access JNIEnv*.

我知道在回调的相同的cpp文件中,有一个功能:

I know that in the same cpp file of the callback, there is a function:

static jboolean init (JNIEnv* env, jobject obj) {...}

我应该在cpp文件的JNIEnv *作为成员变量保存在的init(..)被称为?当回调发生使用它以后呢?

Should I save in the cpp file JNIEnv* as member variable when init(..) is called? and use it later when the callback happens?

很抱歉,但我在JNI初学者。

Sorry but I am a beginner in JNI.

推荐答案

高速缓存的的JNIEnv * 是不是一个特别好的主意,因为你不能使用相同的的JNIEnv * ,并且可能甚至无法使用它在同一线程上的多个本地电话(见的http://android-developers.blogspot.se/2011/11/jni-local-reference-changes-in-ics.html)

Caching a JNIEnv* is not a particularly good idea, since you can't use the same JNIEnv* across multiple threads, and might not even be able to use it for multiple native calls on the same thread (see http://android-developers.blogspot.se/2011/11/jni-local-reference-changes-in-ics.html)

编写可获取的JNIEnv * 并附加当前线程虚拟机,如果必要的并不是太困难的函数:

Writing a function that gets the JNIEnv* and attaches the current thread to the VM if necessary isn't too difficult:

bool GetJniEnv(JavaVM *vm, JNIEnv **env) {
    bool did_attach_thread = false;
    *env = nullptr;
    // Check if the current thread is attached to the VM
    auto get_env_result = vm->GetEnv((void**)env, JNI_VERSION_1_6);
    if (get_env_result == JNI_EDETACHED) {
        if (vm->AttachCurrentThread(env, NULL) == JNI_OK) {
            did_attach_thread = true;
        } else {
            // Failed to attach thread. Throw an exception if you want to.
        }
    } else if (get_env_result == JNI_EVERSION) {
        // Unsupported JNI version. Throw an exception if you want to.
    }
    return did_attach_thread;
}

你会用它的方式是:

The way you'd use it is:

JNIEnv *env;
bool did_attach = GetJniEnv(vm, &env);
// Use env...
// ...
if (did_attach) {
   vm->DetachCurrentThread();
}

您可以在这高度在建设与销毁,RAII式分离的一类包装这样的:

You could wrap this in a class that attaches upon construction and detaches upon destruction, RAII-style:

class ScopedEnv {
public:
    ScopedEnv() : attached_to_vm_(false) {
        attached_to_vm_ = GetJniEnv(g_vm, &env_);  // g_vm is a global
    }

    ScopedEnv(const ScopedEnv&) = delete;
    ScopedEnv& operator=(const ScopedEnv&) = delete;

    virtual ~ScopedEnv() {
        if (attached_to_vm_) {
            g_vm->DetachCurrentThread();
            attached_to_vm_ = false;
        }
    }

    JNIEnv *GetEnv() const { return env_; }

private:
    bool attached_to_env_;
    JNIEnv *env_;
};

// Usage:

{
    ScopedEnv scoped_env;
    scoped_env.GetEnv()->SomeJniFunction();
}
// scoped_env falls out of scope, the thread is automatically detached if necessary

这篇关于什么是保存的JNIEnv的最佳途径*的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆