2011/03/27

[java]JNIからのコールバック

コールバックといえども、関数呼び出しに代わりはなかろう。
関数というか、メソッド呼び出し。
そう考えると、StringBuffer.append()を呼び出したようなしくみでいいはず。

と、自分一人で解決できたように書いているが、そんなことはない。
bitlogさんの記事を見て、ようやくできた。

package com.jnitest;

class Jni {
        public static void main(String[] args) {
                System.out.println("Hello");
                callCallback("callbackFunc");
        }
        
        public void callbackFunc() {
                System.out.println("callback");
        }
        
        static {
                System.loadLibrary("jnicallback");
        }
        
        public static native void callCallback(String funcName);
}


#include "com_jnitest_Jni.h"

JNIEXPORT void JNICALL Java_com_jnitest_Jni_callCallback
  (JNIEnv *env, jclass clazz, jstring funcName)
{
        const char* fname = (*env)->GetStringUTFChars(env, funcName, NULL);

        jclass jc = (*env)->FindClass(env, "com/jnitest/Jni");
        jmethodID mid = (*env)->GetMethodID(env, jc,
                                fname,
                                "()V");
        if(mid) {
                jmethodID ctor = (*env)->GetMethodID(env, jc, "<init>", "()V");
                jobject jo = (*env)->NewObject(env, jc, ctor);

                (*env)->CallVoidMethod(env, jo, mid);

                (*env)->DeleteLocalRef(env, jo);
        } else {
                printf("mid is null.\n");
        }
        (*env)->ReleaseStringUTFChars(env, funcName, fname);
        (*env)->DeleteLocalRef(env, jc);
}

$ java com.jnitest.Jni
Hello
callback


よくわかってないのが、なぜCallVoidMethod()するのにjobjectが必要なのかということ。
NewObject()しているから、これはJava_com_jnitest_Jni_callCallback()を呼び出した人とは別の人になっていると思う。

引数のclazzから取ってくることはできないのかな?
まず、jcを取り除き、clazzに置き換える・・・よし、動いた。

あれ、jclassからオブジェクトを取ってくる関数はないな。
そもそもメソッドなのにjclassが引数で渡されるなんておかしいのでは?

・・・自分でpublic static nativeって書いとるやん。
そしてコールバックして呼び出そうとする方は非staticだ。
これがいかんのですな。

そんなわけで、コールバックする方もstaticにするか、nativeを非staticにするか、だ。
今回はmain()から呼び出すので、コールバックする方をstaticにした。

package com.jnitest;

class Jni {
        public static void main(String[] args) {
                System.out.println("Hello");
                callCallback("callbackFunc");
        }
        
        public static void callbackFunc() {
                System.out.println("callback");
        }
        
        static {
                System.loadLibrary("jnicallback");
        }
        
        public static native void callCallback(String funcName);
}


#include "com_jnitest_Jni.h"

JNIEXPORT void JNICALL Java_com_jnitest_Jni_callCallback
  (JNIEnv *env, jclass clazz, jstring funcName)
{
        const char* fname = (*env)->GetStringUTFChars(env, funcName, NULL);

        jmethodID mid = (*env)->GetStaticMethodID(env, clazz,
                                fname,
                                "()V");
        if(mid) {
                (*env)->CallVoidMethod(env, clazz, mid);
        } else {
                printf("mid is null.\n");
        }
        (*env)->ReleaseStringUTFChars(env, funcName, fname);
}

$ java com.jnitest.Jni
Hello
callback

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。

注: コメントを投稿できるのは、このブログのメンバーだけです。