源碼分析軟鍵盤彈出失效問題

源碼分析軟鍵盤彈出失效問題

平常開發中,經常碰到 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();
            }
        ......
    }

這裏會最終調用 InputMethodManagerServiceshowSoftInput() 方法。 InputMethodManagerServiceIInputMethodManager.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);
    }

來,我們在看下這個 mIWindowManagerinputMethodClientHasFocus

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);
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章