5

Android 向けのインディー ゲームを開発しており、ユーザーにニックネームを選択してもらいたいと考えています。NDK によって提供されるネイティブ アクティビティを使用することを選択しました。これが最も簡単な方法であると思われるからです。

キーボードで最初に遭遇した問題は、関数 ANativeActivity_showSoftInput() がまったく何もしないように見えることでした (ここで説明されているように)。そのため、関数への JNI 呼び出しを使用してキーボードを表示します。

static void showKeyboard(Activity activity) {
  String s = Context.INPUT_METHOD_SERVICE;
  InputMethodManager m = (InputMethodManager)activity.getSystemService(s);
  View w = activity.getWindow().getDecorView();
  m.showSoftInput(w, 0);
}

これは、キーボードを起動するのにうまく機能し、一部のデバイスではすべて一緒にうまく機能します。ただし、他のデバイス (Nexus 7 など) では、ユーザーが「キーボードを非表示」ボタンを押してキーボードを閉じようとすると、次のデバッグ出力でアプリケーションがフリーズします。

I/InputDispatcher(  453): Application is not responding: AppWindowToken{429b54a8 token=Token{42661288 ActivityRecord{41bb0b00 u0 com.example.project/android.app.NativeActivity}}} - Window{420d6138 u0 com.example.project/android.app.NativeActivity}.  It has been 5006.7ms since event, 5005.6ms since wait started.  Reason: Waiting because the focused window has not finished processing the input events that were previously delivered to it.
I/WindowManager(  453): Input event dispatching timed out sending to com.example.project/android.app.NativeActivity

そして、次のようなダイアログ ボックスがユーザーに表示されます。

Project isn't responding. Do you want to close it? [Wait]/[OK]

私たちが明らかに間違っていることはありますか?それともこれはバグでしょうか?このような問題は、キーボード機能がネイティブ グルーに適切に実装されていないことを示しているようです。

余談ですが、まだ多くのデバイスでテストしていませんが、クラッシュしないのは古い Android OS のデバイスです。また、クラッシュするものでは、キーボードが表示されると、戻るボタンがこのようなものからこのようなもの戻る矢印の形のボタンに 変わりますV字型ボタン。おそらくそれは、最初にネイティブ グルーを開発したときには考慮されていなかった別の入力イベントに対応しているのでしょうか? 私はちょうど推測しています。

いずれにせよ、ネイティブ アクティビティを使用しているときにソフト キーボードが動作するようになった場合は、その方法をお知らせください。

乾杯

アップデート

Android のバグとしてここで報告されていますが、回避策についてお知らせいただければ幸いです。あなたもその影響を受けている場合は、その問題に投票することをお勧めします (星印を押してください)。

4

2 に答える 2

3

ピーターのソリューションはうまく機能します。ただし、native_app_glue ファイルを変更したくない場合は、process_input が関数ポインターとして割り当てられていることに注意してください。実装ファイルで、Peter の説明に従って独自の process_input 関数を作成します。

static void process_input( struct android_app* app, struct android_poll_source* source) {
    AInputEvent* event = NULL;
    if (AInputQueue_getEvent(app->inputQueue, &event) >= 0) {
        int type = AInputEvent_getType(event);
        LOGV("New input event: type=%d\n", AInputEvent_getType(event));

        bool skip_predispatch
              =  AInputEvent_getType(event)  == AINPUT_EVENT_TYPE_KEY
              && AKeyEvent_getKeyCode(event) == AKEYCODE_BACK;

        // skip predispatch (all it does is send to the IME)
        if (!skip_predispatch && AInputQueue_preDispatchEvent(app->inputQueue, event)) {
            return;
        }

        int32_t handled = 0;
        if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event);
        AInputQueue_finishEvent(app->inputQueue, event, handled);
    } else {
        LOGE("Failure reading next input event: %s\n", strerror(errno));
    }
}

android_main関数の先頭で、process_inputのバージョンをandroid_app->inputPollSource.processに割り当てます。

イベント ハンドラーで、戻るキー ( AKEYCODE_BACK )を確認し、それをインターセプトして、表示されている場合はキーボードを非表示にします。

この問題は Android 4.1 および 4.2 に存在するように見えることに注意してください - 4.3 で解決されました

于 2013-07-30T18:50:22.457 に答える
2

OK、元の質問の更新で述べたように、これは Android OS のどこかのバグです。私たちは回避策を見つけました。これは本当に醜いですが、機能するので、誰かが役に立つかもしれません。

まず、ファイルを変更する必要があります

<NDK>/sources/android/native_app_glue/android_native_app_glue.c

関数process_inputを次のように変更します。

// When user closes the software keyboard, this function is normally not
// called at all. On the buggy devices, it is called as if AKEYCODE_BACK
// was pressed. This event then gets consumed by the
// AInputQueue_preDispatchEvent. There should be some mechanism that then
// calls the process_input again to finish processing the input.
// But it never does and AInputQueue_finishEvent is never called, the OS
// notices this and closes our app.
static void process_input( struct android_app* app
                         , struct android_poll_source* source) {
    AInputEvent* event = NULL;
    if (AInputQueue_getEvent(app->inputQueue, &event) >= 0) {
        int type = AInputEvent_getType(event);
        LOGV("New input event: type=%d\n", AInputEvent_getType(event));

        int skip_predispatch
              =  AInputEvent_getType(event)  == AINPUT_EVENT_TYPE_KEY
              && AKeyEvent_getKeyCode(event) == AKEYCODE_BACK;

        // TODO: Not sure if we should skip the predispatch all together
        //       or run it but not return afterwards. The main thing
        //       is that the code below this 'if' block will be called.
        if (!skip_predispatch) {
          if (AInputQueue_preDispatchEvent(app->inputQueue, event)) {
              return;
          }
        }

        int32_t handled = 0;
        if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event);
        AInputQueue_finishEvent(app->inputQueue, event, handled);
    } else {
        LOGE("Failure reading next input event: %s\n", strerror(errno));
    }
}

次に、独自の入力イベント ハンドラー内に次のようなコードが必要です。

static int32_t handle_input(android_app* app, AInputEvent* event) {
  int32_t handled = 0;

  struct engine* engine = (struct engine*) app->userData;
  switch (AInputEvent_getType(event)) {
    case AINPUT_EVENT_TYPE_KEY:
      switch (AKeyEvent_getAction(event)) {
        case AKEY_EVENT_ACTION_DOWN:
          int key = AKeyEvent_getKeyCode(event);
          if (os_version_major == 4 && os_version_minor == 2) {
            if (m_keyboard_is_visible && key == AKEYCODE_BACK) {
              // You should set this to true when showing the keyboard.
              m_keyboard_is_visible = false;
              hide_keyboard();
              handled = 1;
              break;
            }
          }
          ... // your own "key down" event handling code.
          break;
      }
      break;
    ...
  }
  return handled;  
}

OS のバージョン番号を取得するには、別の JNI 呼び出しを使用してandroid.os.Build.VERSION.RELEASE android.os.Build.VERSION.SDK_INTから取得します。show_keyboardhide_keyboardを実装するには、この投稿の Ratamovics の回答からの情報を使用します。

android_native_app_glue.c を自動的にコンパイルし、NDK ツリーを直接変更しないようにするには、ファイルをプロジェクトの jni/ ディレクトリにコピーし、Android.mk からこれらの 2 行を削除することをお勧めします。

LOCAL_STATIC_LIBRARIES := android_native_app_glue
$(call import-module,android/native_app_glue)
于 2013-04-12T01:59:41.727 に答える