今回はJavaコード上で作成したオブジェクトをJNIで参照する方法について紹介します。
Javaコード上で生成したオブジェクトをJNIでも参照したい!という場面は、JNIを使用するアプリを作成する場合によく出てくる内容だと思いますが、Webサイトでちょこっと調べても良くわからないというのもよくある場面ではないでしょうか?
今回ご紹介する内容は、そんな場面で参考して頂ければと思います。
※JNIの基本的な使い方やそのサンプルについて、こちらに記事をアップしています。
よろしければ、こちらも参照下さればと思います。
それでは、早速サンプルコードを見ていきましょう。
Java→JNIへ渡ったオブジェクトの値をJNIで参照する為に必要な手順は、以下の通りとなります。
- オブジェクトへの参照(ポインタ)からクラス定義をロードする
- クラス定義からアクセス用のIDを取得する
-
オブジェクトへの参照からアクセス用のIDを用いて値を取得する
○Javaソース
ここでは、Testクラスを引数に持つnativeメソッド(debug())を実行します。
public class TestJniActivity extends Activity {
// Nativeメソッド
private native void debug(Test o);
/**
* ライブラリロード
*/
static {
loadLib();
}
/**
* JNIへInputするデータクラス
*/
public class Test {
int val;
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// JNIへInputするデータクラスを作成
Test tes = new Test();
// 作成したデータクラスのメンバ変数に値を設定
tes.val = 123;
// JNI実行
debug(tes);
}
/**
* ライブラリロード
*/
static void loadLib() {
// Nativeライブラリをロード
System.loadLibrary("hello-jni");
}
}
○Cソース(JNIソース)
Javaコードから入力されたオブジェクトを参照して値を取得します。 ちなみに、JavaとNativeのインタフェースとなるクラスの第2引数【thiz】は、TestJniActivityオブジェクトへの参照(ポインタ)で、
【o】はTestオブジェクトへの参照となります。 つまりNativeメソッドにはオブジェクトの実態に対する参照が入力されることになります。
#include <stdio.h>
#include <jni.h>
#include <android/log.h>
#define LOG(...) (__android_log_print( \
ANDROID_LOG_DEBUG, \
"testJNI", \
__VA_ARGS__))
void Java_hoge_test_jni_TestJniActivity_debug(JNIEnv* env,
jobject thiz,
jobject o) {
// クラス定義をロードする
jobect clz2 = (*env)->GetObjectClass(env, o);
// クラス定義から『val』のアクセスIDを取得する
jfieldID field_id = (*env)->GetFieldID(env, clz2, "val", "I");
// アクセスIDを用いて値をロードする
jint value = (*env)->GetIntField(env, o, field_id);
LOG("#### value = %d ####", value);
return;
}
○makeファイル
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := testjni_sample.c
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
参考にしたサイトおよび資料