使用JNI从单独的线程调用静态Java方法 [英] Call static Java method from separate thread using JNI

查看:104
本文介绍了使用JNI从单独的线程调用静态Java方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在android中使用JNI来创建一个函数指针,而我正在使用的本机库将其转发给java.

I'm trying to use JNI in android to make a function pointer that a native library I'm using uses forward it's call to java.

当调用initializeStateController时,将使用pthread_create创建一个新线程,只要状态控制器的状态发生变化,该线程就会调用函数指针.

When initializeStateController is called, a new thread is made using pthread_create that calls the function pointer whenever the state of the State Controller changes.

但是,当我尝试从C中的state_exec调用GetStaticMethodID时,出现以下错误:

However, when I try to call GetStaticMethodID from state_exec in C, I'm getting the following error:

JNI DETECTED ERROR IN APPLICATION: jclass is an invalid local reference: 0xec500019 (0xdead4321) in call to GetStaticMethodID

这是我当前的代码:

C代码

state_controller *controller;
JavaVM* gJvm = NULL;
static jclass sc_class;

JNIEnv* getEnv() {
    JNIEnv *env;
    int status = (*gJvm)->GetEnv(gJvm, (void**)&env, JNI_VERSION_1_6);
    if(status < 0) {
         status = (*gJvm)->AttachCurrentThread(gJvm, &env, NULL);
        if(status < 0) {
            return NULL;
        }
    }
    return env;
}

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* pjvm, void* reserved) {
    gJvm = pjvm;
    JNIEnv *env = getEnv();

    sc_class = (*env)->FindClass(env, "com/my/package/StateController");

    return JNI_VERSION_1_6;
}

int state_exec(int state, int from) {
    JNIEnv *env = getEnv();
    jmethodID mid = (*env)->GetStaticMethodID(env, sc_class, "stateExec","(II)I");
    jint result = (*env)->CallStaticIntMethod(env, sc_class, mid, state, from);

    return (int) result;
}

// This part is unimportant.
// This is just where I hand the function pointer
// to the library to use.

JNIEXPORT void JNICALL 
Java_com_my_package_StateController_initializeStateController
(
        JNIEnv *env,
        jobject jobj
) {
    controller = new_state_controller(
        state_exec
    );
    sc_start_controller(controller);
}

Java

package com.my.package;

class StateController {

    public native void initializeStateController();

    public static int stateExec(int state, int from) {
        Log.d("StateTest", "State " + state + " -> " + from);
        return 0;
    }
}

. . . 

(new StateController()).initializeStateController();

推荐答案

事实证明,FindClass方法仅返回本地引用,而不返回全局引用.为了使这项工作,您需要使其成为全局参考.您可以按照以下说明进行操作.

It turns out that the FindClass method only returns local references, not global. In order to make this work you need to make it a global reference. You can do this as demonstrated below.

// Replace

    sc_class = (*env)->FindClass(env, "com/my/package/StateController");

// With

    sc_class = (*env)->NewGlobalRef(
        env, 
        (*env)->FindClass(
            env, 
            "com/my/package/StateController"
        )
    );

// Later when you are done with the class reference, run this to free it.

    (*env)->DeleteGlobalRef(env, sc_class);

来自Android文档:

From Android Docs:

错误:错误地认为FindClass()返回全局引用

Bug: Mistakenly assuming FindClass() returns global references

FindClass()返回本地引用.许多人认为不是.在没有类卸载的系统中(例如Android),您可以将jfieldID和jmethodID视为全局的. (它们实际上不是引用,但是在具有类卸载功能的系统中,存在类似的生存期问题.)但是jclass是引用,而FindClass()返回本地引用.常见的错误模式是静态jclass".除非您手动将本地引用转换为全局引用,否则代码将被破坏.

FindClass() returns local references. Many people assume otherwise. In a system without class unloading (like Android), you can treat jfieldID and jmethodID as if they were global. (They’re not actually references, but in a system with class unloading there are similar lifetime issues.) But jclass is a reference, and FindClass() returns local references. A common bug pattern is "static jclass". Unless you’re manually turning your local references into global references, your code is broken.

https://android -developers.googleblog.com/2011/11/jni-local-reference-changes-in-ics.html

这篇关于使用JNI从单独的线程调用静态Java方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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