NativeActivityクラスを使用してAndroidでOpenGLゲームを開発しています。これまでのところすべてのことがOKになりましたが、今はJavaから利用できるように思われる機能にアクセスする必要があります。Android:NativeActivityのJNIを使用
私たちが最初に考えたのは、ディスプレイDPIにアクセスするのに便利だと思ったことがあります。このようにhereは、Javaコードは次のようになります。
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
そして、ここで不幸に対応するC++コードです:
// My checking routine.
#define JNI_ASSERT(jni, cond) { \
if (!(cond)) {\
std::stringstream ss; \
ss << __FILE__ << ":" << __LINE__; \
throw std::runtime_error(ss.str()); \
} \
if (jni->ExceptionCheck()) { \
std::stringstream ss; \
ss << __FILE__ << ":" << __LINE__; \
throw std::runtime_error("Exception: " + ss.str()); \
} \
}
void print_dpi(android_app* app) {
JNIEnv* jni;
app->activity->vm->AttachCurrentThread(&jni, NULL);
jclass activityClass = jni->FindClass("android/app/NativeActivity");
JNI_ASSERT(jni, activityClass);
jmethodID getWindowManager = jni->GetMethodID
(activityClass
, "getWindowManager"
, "()Landroid/view/WindowManager;");
JNI_ASSERT(jni, getWindowManager);
jobject wm = jni->CallObjectMethod(app->activity->clazz, getWindowManager);
JNI_ASSERT(jni, wm);
jclass windowManagerClass = jni->FindClass("android/view/WindowManager");
JNI_ASSERT(jni, windowManagerClass);
jmethodID getDefaultDisplay = jni->GetMethodID(windowManagerClass
, "getDefaultDisplay"
, "()Landroid/view/Display;");
JNI_ASSERT(jni, getDefaultDisplay);
jobject display = jni->CallObjectMethod(wm, getDefaultDisplay);
JNI_ASSERT(jni, display);
jclass displayClass = jni->FindClass("android/view/Display");
JNI_ASSERT(jni, displayClass);
// Check if everything is OK so far, it is, the values it prints
// are sensible.
{
jmethodID getWidth = jni->GetMethodID(displayClass, "getWidth", "()I");
JNI_ASSERT(jni, getWidth);
jmethodID getHeight = jni->GetMethodID(displayClass, "getHeight", "()I");
JNI_ASSERT(jni, getHeight);
int width = jni->CallIntMethod(display, getWidth);
JNI_ASSERT(jni, true);
log("Width: ", width); // Width: 320
int height = jni->CallIntMethod(display, getHeight);
JNI_ASSERT(jni, true);
log("Height: ", height); // Height: 480
}
jclass displayMetricsClass = jni->FindClass("android/util/DisplayMetrics");
JNI_ASSERT(jni, displayMetricsClass);
jmethodID displayMetricsConstructor = jni->GetMethodID(displayMetricsClass
, "<init>", "()V");
JNI_ASSERT(jni, displayMetricsConstructor);
jobject displayMetrics = jni->NewObject(displayMetricsClass
, displayMetricsConstructor);
JNI_ASSERT(jni, displayMetrics);
jmethodID getMetrics = jni->GetMethodID(displayClass
, "getMetrics"
, "(Landroid/util/DisplayMetrics;)V");
JNI_ASSERT(jni, getMetrics);
jni->CallVoidMethod(display, getMetrics, displayMetrics);
JNI_ASSERT(jni, true);
{
jfieldID xdpi_id = jni->GetFieldID(displayMetricsClass, "xdpi", "F");
JNI_ASSERT(jni, xdpi_id);
float xdpi = jni->GetFloatField(displayMetricsClass, xdpi_id);
JNI_ASSERT(jni, true);
log("XDPI: ", xdpi); // XDPI: 0
}
{
jfieldID height_id = jni->GetFieldID(displayMetricsClass
, "heightPixels", "I");
JNI_ASSERT(jni, height_id);
int height = jni->GetIntField(displayMetricsClass, height_id);
JNI_ASSERT(jni, true);
log("Height: ", height); // Height: 0
}
// TODO: Delete objects here.
app->activity->vm->DetachCurrentThread();
}
コード出力:
Width: 320
Height: 480
XDPI: 0
Height: 0
それはdisplayMetricsかのようです呼び出しでオブジェクトが設定されていません
jni->CallVoidMethod(display, getMetrics, displayMetrics);
JNIで引数を戻り値として使用できない場合がありますか?もしそうなら、私たちがNativeActivityグルーを使用していることを考えれば、どうすればそれを回避できますか?
Eew!ハードコアなJNIをやってからしばらくしていますが、私は同じような間違いを思い出しています。それは常にコーヒーをつかみ、新しい目で戻ってくるのに役立ちます! – Cliff