输入法弹出入口有 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
中在四种情况下会调用。