1. 输入法的弹出

1.1 InputMethodManager.showSoftInput()

输入法弹出入口有 TextViewSearchViewNumberPicker 等。这几个控件都是调用 InputMethodManagershowSoftInput() 方法弹出的。

TextViewonTouchView() 方法中,如果满足情况会调用 showSoftInput() 方法。

if (touchIsFinished && (isTextEditable() || textIsSelectable)) {
    // Show the IME, except when selecting in read-only text.
    final InputMethodManager imm = InputMethodManager.peekInstance();
    viewClicked(imm);
    if (isTextEditable() && mEditor.mShowSoftInputOnFocus && imm != null) {
        imm.showSoftInput(this, 0);
    }
}

1.2 InputMethodManager.mServiceView

showSoftInput() 方法中 mServedView 和传入的 View 对象要一致,否则返回 false。mServedView 指的是输入法正在服务的 View 对象,其实就是接收输入法输入操作的 View 对象

最终会调用 InputMethodManagerServiceshowSoftInput() 方法弹出输入法窗口。

public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) {
    checkFocus();
    synchronized (mH) {
        if (mServedView != view && (mServedView == null
                || !mServedView.checkInputConnectionProxy(view))) {
            return false;
        }
        try {
            return mService.showSoftInput(mClient, flags, resultReceiver);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
}}}

checkFocusNoStartInput() 方法中把 mNextServedView 赋值给了 mServedViewmNextServedView 是在 focusInLocked() 方法中赋值的。

private boolean checkFocusNoStartInput(boolean forceNewFocus) {
    // This is called a lot, so short-circuit before locking.
    if (mServedView == mNextServedView && !forceNewFocus) {
        return false;
    }
    synchronized (mH) {
        if (mServedView == mNextServedView && !forceNewFocus) {
            return false;
        }
        mServedView = mNextServedView;
    }
    return true;
}

void focusInLocked(View view) {
    mNextServedView = view;
    scheduleCheckFocusLocked(view);
}

focusInLocked() 方法中最后调用的 scheduleCheckFocusLocked() 方法会调用 ViewRootIml 对象的 dispatchCheckFocus() 方法,而这个方法会向 Handler 发送消息,最终会调用 InputMethodManagercheckFocus() 方法。在 checkFocus() 方法中会调用上面的提到的 checkFocusNoStartInput() 方法,就会把获取焦点的 View 对象设置为 mServedView 了。

// android.view.inputmethod.InputMethodManager
static void scheduleCheckFocusLocked(View view) {
    ViewRootImpl viewRootImpl = view.getViewRootImpl();
    if (viewRootImpl != null) {
        viewRootImpl.dispatchCheckFocus();
}}

// android.view.ViewRootImpl
public void dispatchCheckFocus() {
    if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
        // This will result in a call to checkFocus() below.
        mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
}}

final class ViewRootHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        case MSG_CHECK_FOCUS: {
            InputMethodManager imm = InputMethodManager.peekInstance();
            if (imm != null) {
                imm.checkFocus();
            }
        } break;
}}

如果 checkFocusNoStartInput() 方法返回 true,则调用 startInputInner() 方法,该方法会建立 InputConnection 把输入法和 View 绑定起来。

// android.view.inputmethod.InputMethodManager
public void checkFocus() {
    if (checkFocusNoStartInput(false)) {
        startInputInner(InputMethodClient.START_INPUT_REASON_CHECK_FOCUS, null, 0, 0, 0);
}}

1.3 InputMethodManager.focusInLocked()

上面提到调用 focusInLocked() 方法后,最终会把参数 View 对象赋值给 mServedView。该方法有两个地方调用,一个是 focusIn() 方法,一个是 onPostWindowFocus() 方法。

1.3.1 InputMethodManager.focusIn()

focusIn() 方法是在 View 中在四种情况下会调用。