输入法弹出入口有 TextView、SearchView、NumberPicker 等。这几个控件都是调用 InputMethodManager 的 showSoftInput() 方法弹出的。
TextView 的 onTouchView() 方法中,如果满足情况会调用 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);
}
}
showSoftInput() 方法中 mServedView 和传入的 View 对象要一致,否则返回 false。mServedView 指的是输入法正在服务的 View 对象,其实就是接收输入法输入操作的 View 对象
最终会调用 InputMethodManagerService 的 showSoftInput() 方法弹出输入法窗口。
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 赋值给了 mServedView。mNextServedView 是在 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 发送消息,最终会调用 InputMethodManager 的 checkFocus() 方法。在 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);
}}
上面提到调用 focusInLocked() 方法后,最终会把参数 View 对象赋值给 mServedView。该方法有两个地方调用,一个是 focusIn() 方法,一个是 onPostWindowFocus() 方法。
focusIn() 方法是在 View 中在四种情况下会调用。