EditText中输入键1,系统发生了什么?
按键会触发触发消息,发送到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值并发送TextWatcher消息

浙公网安备 33010602011771号