源碼分析軟鍵盤彈出失效問題
平常開發中,經常碰到 EditText
輸入內容時需要調起軟件盤。但是有時發現調用了之後沒有生效,軟鍵盤並沒有彈出來。通常做法如下,延遲執行,雖然大概率提升了軟鍵盤彈出的機率,但是偶爾還是會失效,沒有從根本上解決問題的痛點。
editTextView.postDelayed(new Runnable() {
@Override
public void run() {
InputMethodManager manager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
manager.showSoftInput(editTextView, 0);
}
},500);
下面我們就從源碼着手來分析一下問題所在。InputMethodManager
管理者輸入相關邏輯,自然就包括軟鍵盤的顯示與隱藏,我們從 showSoftInput()
方法作爲入口來看。
InputMethodManager.java
final IInputMethodManager mService;
public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) {
......
try {
return mService.showSoftInput(mClient, flags, resultReceiver);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
......
}
這裏會最終調用 InputMethodManagerService
的 showSoftInput()
方法。 InputMethodManagerService
爲 IInputMethodManager.Stub
的一個實現類
InputMethodManagerService.java
@Override
public boolean showSoftInput(IInputMethodClient client, int flags,
ResultReceiver resultReceiver) {
......
// We need to check if this is the current client with
// focus in the window manager, to allow this call to
// be made before input is started in it.
//檳果~~~大致意思就是,這玩意在這裏會檢查一下當前 window 的焦點,
//如果沒有獲取焦點的話,直接返回 false 就失效了 - -!
if (!mIWindowManager.inputMethodClientHasFocus(client)) {
return false;
}
......
return showCurrentInputLocked(flags, resultReceiver);
}
來,我們在看下這個 mIWindowManager
的 inputMethodClientHasFocus
WindowManagerService.java
@Override
public boolean inputMethodClientHasFocus(IInputMethodClient client) {
synchronized (mWindowMap) {
// TODO: multi-display
//通過默認的顯示設備的焦點進行判斷,因爲開始流行牛逼的分屏了。。哈哈
if (getDefaultDisplayContentLocked().inputMethodClientHasFocus(client)) {
return true;
}
// Okay, how about this... what is the current focus?
// It seems in some cases we may not have moved the IM
// target window, such as when it was in a pop-up window,
// so let's also look at the current focus. (An example:
// go to Gmail, start searching so the keyboard goes up,
// press home. Sometimes the IME won't go down.)
// Would be nice to fix this more correctly, but it's
// way at the end of a release, and this should be good enough.
// 這段話的大致意思就是 他們通過這個修復了一個系統的bug,
// 進入 郵件app ,彈出軟鍵盤,立即安 home 鍵返回,
// 這個時候軟鍵盤還在,不符合預期
if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null
&& mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
return true;
}
}
return false;
}
到這裏我們就大致明白爲啥軟鍵盤有時候沒有彈出來呢,就是當前 window
沒有獲取到焦點,即當前 window
是否已經完全在當前屏幕上顯示出來。
原理我們已經瞭解了,具體怎麼解決呢。其實,不管在 Activity
中,或者在 View
中都有一個 onAttachedToWindow()
方法。所以,在這個方法中調起軟鍵盤就可以正常顯示了。
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
InputMethodManager manager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
manager.showSoftInput(editTextView, 0);
}