按键会触发触发消息,发送到MessageQueue中,消息内容为:
{ when=-20s330ms what=11 obj=KeyEvent { action=ACTION_DOWN, keyCode=KEYCODE_1, scanCode=0, metaState=0, flags=0x6, repeatCount=0, eventTime=3939450, downTime=3939450, deviceId=-1, source=0x0 } target=android.view.ViewRootImpl$ViewRootHandler }
这条消息在ViewRootImpl$ViewRootHandler中处理,对应的hanleMessage部分为
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DISPATCH_KEY_FROM_IME: {
if (LOCAL_LOGV) Log.v(
TAG, "Dispatching key "
+ msg.obj + " from IME to " + mView);
KeyEvent event = (KeyEvent)msg.obj;
if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
// The IME is trying to say this event is from the
// system! Bad bad bad!
//noinspection UnusedAssignment
event = KeyEvent.changeFlags(event, event.getFlags() &
~KeyEvent.FLAG_FROM_SYSTEM);
}
enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
} break;
在ViewRootImpl中跳转几次后进入processKeyEvent方法
private int processKeyEvent(QueuedInputEvent q) {
final KeyEvent event = (KeyEvent)q.mEvent;
// Deliver the key to the view hierarchy.
// 调用了View的dispatchKeyEvent方法,其中mView是PhoneWindow$DecorView
if (mView.dispatchKeyEvent(event)) {
return FINISH_HANDLED;
}
//.....
return FORWARD;
}
从DecorView开始执行若干次dispatchKeyEvent(event),将KeyEvent最终分发到TextView中执行TextView的onKeyDown()方法:
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
int which = doKeyDown(keyCode, event, null);
if (which == 0) {
return super.onKeyDown(keyCode, event);
}
return true;
}
在onKeyDown()方法的一开始执行了TextView的doKeyDown()
public boolean onKeyDown(int keyCode, KeyEvent event) {
int which = doKeyDown(keyCode, event, null);
if (which == 0) {
return super.onKeyDown(keyCode, event);
}
return true;
}
这个函数第一行执行TextView的doKeyDown()方法,跟踪进去
private int doKeyDown(int keyCode, KeyEvent event, KeyEvent otherEvent)『
if (mEditor != null && mEditor.mKeyListener != null) {
if (doDown) {
beginBatchEdit();
final boolean handled = mEditor.mKeyListener.onKeyDown(this, (Editable) mText,
keyCode, event);
endBatchEdit();
hideErrorIfUnchanged();
if (handled) return 1;
}
}
}
这个方法执行那个了mKeyListerner.onKeyDown()方法:
@Override
public boolean onKeyDown(View view, Editable content,
int keyCode, KeyEvent event) {
KeyListener im = getKeyListener(event);
return im.onKeyDown(view, content, keyCode, event);
}
通过getKeyListener(event)来判断KeyEvent对应的KeyListener,然后执行对应的onKeyDown。
对于按键1,对于的KeyListener为QwertyKeyListener,QwertyKeyListener.onKeyDown()为:
public boolean onKeyDown(View view, Editable content,
int keyCode, KeyEvent event) {
//...
content.replace(selStart, selEnd, String.valueOf((char) i));
//...
}
这其中调用了SpannableStringBuilder的replace方法:
public SpannableStringBuilder replace(final int start, final int end,
CharSequence tb, int tbstart, int tbend) {
//...
TextWatcher[] textWatchers = getSpans(start, start + origLen, TextWatcher.class);
sendBeforeTextChanged(textWatchers, start, origLen, newLen);
change(start, end, tb, tbstart, tbend);
//...
sendTextChanged(textWatchers, start, origLen, newLen);
sendAfterTextChanged(textWatchers);
// Span watchers need to be called after text watchers, which may update the layout
sendToSpanWatchers(start, end, newLen - origLen);
return this;
}
这个方法获得了TextView所有的TextWatcher,然后发送BeforeTextChanged消息,之后调用change()方法真正
改变了TextView中的内容。然后发送OnTextChanged和AfterTextChanged方法。
这样一个流程可以简单概括成这样几步:
1.按下键盘后系统发送一个KeyDown的消息到MainLooper的MessageQueue.
2.ViewRootImpl$ViewRootHandler处理KeyDown消息,调用DecorView的dispatchKeyEvent进行分发
3.DocoreView将KeyEvent分发到TextView执行TextView的doKeyDown()方法。
4.TextView调用mKeyListener.onKeyDown()方法。
5.最终调用合适的KeyListener(这儿为QwertyKeyListener)的onKeyDown()方法,改变TextView中的mText值