2013-04-09 16 views
5

アンドロイド用のインディーゲームを開発しており、ユーザーにニックネームを選択させたいと考えています。私たちは、NDKが提供するネイティブアクティビティを使用することを選択しました。これは、最も簡単な方法です。ネイティブアクティビティを使用中にソフトキーボードを閉じるとクラッシュする

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); 
} 

我々はキーボードで出会った最初の問題は、関数の呼び出し機能はANativeActivity_showSoftInputは、()(説明などhereなど)まったく何もしないように見えるので、私たちは、JNIを使​​用してキーボードを持ち出すということでした

これはキーボードの起動には問題ありません。一部のデバイスでは正常に動作します。しかし、ユーザーはアプリケーションがこのデバッグ出力でフリーズ「隠すキーボード」ボタンを押すことで、キーボードを閉じようとする他のデバイス(例えばネクサス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] 

明らかに間違っていることはありますか?これはバグかもしれませんか? this oneのような問題は、キーボードの機能性がネイティブグルーに適切に実装されたことがないように思われます。

まだ、多くのデバイスでテストされていませんが、クラッシュしないものは古いAndroid OSのものです。また、キーボードが表示されてもクラッシュするキーボードでは、の背面にあるボタンは、backward arrow shaped buttonのようなものから V shaped buttonのように変わります。おそらく、それはネイティブの接着剤を最初に開発したときに考慮されなかった別の入力イベントに対応していますか?私はちょうど推測している。

ネイティブアクティビティを使用している間にソフトキーボードが動作していた場合は、どのように行ったか教えてください。

乾杯

それは、Android hereにバグとして報告されているUPDATE

、我々はまだかかわらず、回避策を聞いて幸せになります。あなたもそれによって影響を受けている場合は、(スターを押すことで)その問題に関する投票をしたいかもしれません。

答えて

3

ピーターのソリューションはうまくいきます。ただし、native_app_glueファイルを変更しない場合は、process_inputが関数ポインタとして割り当てられていることに注意してください。 inputPollSource.process>

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機能の開始時に、android_app-にprocess_inputのバージョンを割り当てる:あなたの実装ファイルには、ピーターによって記載されているように、独自のprocess_input関数を作成します。

イベントハンドラでは、背面キー(AKEYCODE_BACK)を確認し、表示されている場合はキーボードを隠すように傍受してください。この問題は、Android 4.1と4.2に存在するように見えること

注 - 私は、Android 4.2でNexus 4の上でこの問題を持っている4.3

+0

私はそれを完全に逃しました、Cファイルにパッチを当てるよりはるかに良い、ありがとう。 –

+0

偶然、今日Nexusのアップグレードを受け取りました。問題はAndroid 4.3で修正されているようです。あなたの提案は、Androidのバージョンが4.2の場合にのみ、patch_process_input関数の適用を容易にします。必要に応じて、あなたと私の答えを組み合わせて、他の人のための最終的な解決策を提供することができます。私は最終的な答えとしてマークします。そうでなければ、私が覚えていれば、私は来週いつかそれをやろうとします。乾杯。 –

+0

確かに更新されました。私はまた、問題が4.3で修正されていることに気づいた!それはしばらくの間、4.1および4.2の電話機で市場に残っています... – krsteeve

2

私の元の質問の更新に記載されているように、これはAndroid OSのどこかのバグです。私たちは回避策を見つけました。本当に醜いですが、誰かが役に立つと思うように機能します。そして、あなたはこのようになりますコードを持っている必要があり

// 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)); 
    } 
} 

まず、関数にこのように見えるようにprocess_inputを変更することで、ファイル

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

を変更する必要があります自分の入力イベントハンドラの内部:

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.RELEASEandroid.os.Build.VERSION.SDK_INTから取得します。show_keyboardを実装するにはhide_keyboard Ratamovicsの情報をthisの投稿に使用してください。 android_native_app_glue.cが自動的にコンパイルしているとし、NDKツリーに直接変更を行うことを避けるために

NOTE、あなたのプロジェクトのJNI /ディレクトリにファイルをコピーし、あなたのAndroidからこれらの2行を捨てしたい場合があります。 mk

LOCAL_STATIC_LIBRARIES := android_native_app_glue 
$(call import-module,android/native_app_glue) 
+0

で解決しました。この問題を文書化していただきありがとうございます! – Gaetan

関連する問題