Как вызвать функцию Java из c - PullRequest
4 голосов
/ 16 февраля 2012

Я застрял с этим, мне нужно вызвать функцию Java из c / c ++.

В примерах и руководствах я вижу только приложение Java, вызывающее метод ac, и в этом же методе вызывающее другойметод Java, но я хочу вызвать метод Java из любой части кода.Вот что у меня есть:

static JNIEnv mEnv;
static jclass mClassAndroidActivity;
static mMethodSayHello;
JNIEXPORT void JNICALL JNI_FUNCTION(AndroidActivity_nativeInit)(JNIEnv* env, jobject obj, int width, int height)
{
    mEnv = env;
    jclass cls = (*env)->GetObjectClass(env, obj);
    mClassAndroidActivity = (*env)->NewGlobalRef(env, cls);
    mMethodSayHello = (*env)->GetMethodID (env, mClassAndroidActivity, "SayHello", "(Ljava/lang/String;)V");
}

//this method is called from a cpp
void nativeSayHello(char* msg)
{
    jstring string = (*mEnv)->NewStringUTF(mEnv, msg);
    (*mEnv)->CallVoidMethod(mEnv, mClassAndroidActivity, mMethodSayHello, string);
}

, но всегда происходит сбой, я пытался без NewGlobalRef, используя mEnv вместо env в JNI_Function, я пытался получить идентификатор метода из JNI_OnLoad, новсегда дает сбой.

Это журнал, который я получаю:

02-15 18: 09: 48.520: W / dalvikvm (27904): ПРЕДУПРЕЖДЕНИЕ JNI: threadid = 1, используя env из threadid = 0

1 Ответ

9 голосов
/ 16 февраля 2012

Вы не можете повторно использовать JNIEnv, потому что это относится к вызывающему потоку.Чтобы вызвать (нестатический) Java-метод из собственного кода, вам нужно что-то вроде этого:

static JavaVM *gJavaVM;
static jobject gCallbackObject = NULL;

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

JNIEXPORT void JNICALL JNI_FUNCTION(AndroidActivity_nativeInit)(JNIEnv* env, jobject obj, int width, int height) {
    // ...
    gCallbackObject = (*env)->NewGlobalRef(env, obj);
}

JNIEXPORT void JNICALL JNI_FUNCTION(AndroidActivity_nativeRelease)(JNIEnv* env, jobject obj) {
    (*env)->DeleteGlobalRef(env, gCallbackObject);
    gCallbackObject = NULL;
}

//this method is called from native code
void nativeSayHello(char* msg) {
    int status;
    JNIEnv *env;
    int isAttached = 0;

    if (!gCallbackObject) return;

    if ((status = (*gJavaVM)->GetEnv(gJavaVM, (void**)&env, JNI_VERSION_1_6)) < 0) {
        if ((status = (*gJavaVM)->AttachCurrentThread(gJavaVM, &env, NULL)) < 0) {
            return;
        }
        isAttached = 1;
    }

    jclass cls = (*env)->GetObjectClass(env, gCallbackObject);
    if (!cls) {
        if (isAttached) (*gJavaVM)->DetachCurrentThread(gJavaVM);
        return;
    }

    jmethodID method = (*env)->GetMethodID(env, cls, "SayHello", "(Ljava/lang/String;)V");
    if (!method) {
        if (isAttached) (*gJavaVM)->DetachCurrentThread(gJavaVM);
        return;
    }

    jstring string = (*mEnv)->NewStringUTF(mEnv, msg);
    (*env)->CallVoidMethod(env, gCallbackObject, method, string);

    if (isAttached) (*gJavaVM)->DetachCurrentThread(gJavaVM);
}

Этот фрагмент кода не тестировался.Чтобы предотвратить утечку памяти, не забудьте вызвать метод nativeRelease() в вашем коде Java, когда ссылка на объект больше не понадобится.

См. Документация по собственному интерфейсу Java дляболее подробная информация.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...