概述
android的input系统大概可以分为三个部分,按照事件的产生和消费顺序是:硬件->内核–>framework–>应用
1,设备硬件,包括屏幕,鼠标,键盘等等。
2,内核驱动,linux内核将事件写入/dev/input的节点。
3,Framework,也可以划分为native层和java层,native层拿到事件后封装并交给java层。
4,应用app,消费事件,针对不同事件来做出不同反馈。
其中3,4是作为Android Framework开发人员重点研究的方向,4更是所有Android从业人员需要掌握的基础技能。
本章源码基于AOSP android 7.1.2 ,点击查看
开头
耐不住对源码的好奇,我先通过这篇文章概况下Framework的java层收到native传递过来的事件后,是怎样一步步分发到view的,开始之前请先关注这个类。
这很重要,它就是Framework处理事件中的一个转折点,承接native和java这两层的中间态。
阅读源码还是坚持那个原则,不沉溺细节,抽取重点。先形成一个骨架,后面再慢慢丰富细节。
1,ViewRootImpl:“我很重要,都在我这里”
InputEventReceiver是一个抽象类,ViewRootImpl中的WindowInputEventReceiver实现了它,那么这里就是处理事件的入口之一,ViewRootImpl是一个很重要的角色,像窗口管理,视图管理,事件分发等任务都和它有关联,本篇文章的讨论基本都在它的范围内。
//frameworks/base/core/java/android/view/ViewRootImpl.java
6343 final class WindowInputEventReceiver extends InputEventReceiver {
....
6348 @Override
6349 public void onInputEvent(InputEvent event) {
6350 enqueueInputEvent(event, this, 0, true);
6351 }
}
很明显,看到event紧接着到了enqueueInputEvent这个方法。
6159 void enqueueInputEvent(InputEvent event,
6160 InputEventReceiver receiver, int flags, boolean processImmediately) {
....
//processImmediately为false,事件加入到消息队列中,然后按顺序处理。
//processImmediately为true,立即处理,然后按顺序处理,最终都会调用到doProcessInputEvents。
6181 if (processImmediately) {
6182 doProcessInputEvents();
6183 } else {
6184 scheduleProcessInputEvents();
6185 }
6186 }
6197 void doProcessInputEvents() {
6198 // Deliver all pending input events in the queue.
6199 while (mPendingInputEventHead != null) {
...
6221 deliverInputEvent(q);
6222 }
....
6230 }
6232 private void deliverInputEvent(QueuedInputEvent q) {
...
6239 InputStage stage;
...
6246 if (stage != null) {
6247 stage.deliver(q);
6248 } else {
6249 finishInputEvent(q);
6250 }
6251 }
不得不认识一下InputStage,根据注释,它是定义了一个责任链,它的实现子类都在ViewRootImpl中
3821 /**
3822 * Base class for implementing a stage in the chain of responsibility
3823 * for processing input events.
3824 * <p>
3825 * Events are delivered to the stage by the {@link #deliver} method. The stage
3826 * then has the choice of finishing the event or forwarding it to the next stage.
3827 * </p>
3828 */
3829 abstract class InputStage {
3830 private final InputStage mNext;
....
3836 /**
3837 * Creates an input stage.
3838 * @param next The next stage to which events should be forwarded.
3839 */
3840 public InputStage(InputStage next) {
3841 mNext = next;
3842 }
3843
....
3898 /**
3899 * Called when an event is being delivered to the next stage.
3900 */
3901 protected void onDeliverToNext(QueuedInputEvent q) {
3902 if (DEBUG_INPUT_STAGES) {
3903 Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);
3904 }
3905 if (mNext != null) {
3906 mNext.deliver(q);
3907 } else {
3908 finishInputEvent(q);
3909 }
3910 }
...
3950 }
责任链在setView方法中建立,负责对事件进行预处理等操作,最终的责任链:mSyntheticInputStage --> viewPostImeStage --> nativePostImeStage --> earlyPostImeStage --> imeStage --> viewPreImeStage --> viewPreImeStage,本章不做研究。
743 // Set up the input pipeline.
744 CharSequence counterSuffix = attrs.getTitle();
745 mSyntheticInputStage = new SyntheticInputStage();
746 InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
747 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
748 "aq:native-post-ime:" + counterSuffix);
749 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
750 InputStage imeStage = new ImeInputStage(earlyPostImeStage,
751 "aq:ime:" + counterSuffix);
752 InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
753 InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
754 "aq:native-pre-ime:" + counterSuffix);
755
756 mFirstInputStage = nativePreImeStage;
757 mFirstPostImeInputStage = earlyPostImeStage;
这里我们只关注ViewPostImeInputStage,名如其意,就是用来负责给view发送事件的,那么到这里,可以看到它内部的processKeyEvent,processPointerEvent,processTrackballEvent,processGenericMotionEvent这几个方法调用了mView的dispatchKeyEvent,dispatchPointerEvent等方法,其实就是到了View了,因为mView正是那个它,DecorView。
4291 /**
4292 * Delivers post-ime input events to the view hierarchy.
4293 */
4294 final class ViewPostImeInputStage extends InputStage {
4295 public ViewPostImeInputStage(InputStage next) {
4296 super(next);
4297 }
4298
4299 @Override
4300 protected int onProcess(QueuedInputEvent q) {
4301 if (q.mEvent instanceof KeyEvent) {
4302 return processKeyEvent(q);
4303 } else {
4304 final int source = q.mEvent.getSource();
4305 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
4306 return processPointerEvent(q);
4307 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
4308 return processTrackballEvent(q);
4309 } else {
4310 return processGenericMotionEvent(q);
4311 }
4312 }
4313 }
4314
4327 private int processKeyEvent(QueuedInputEvent q) {
4328 final KeyEvent event = (KeyEvent)q.mEvent;
4329
4330 // Deliver the key to the view hierarchy.
4331 if (mView.dispatchKeyEvent(event)) {
4332 return FINISH_HANDLED;
4333 }
...
4344 if (mView.dispatchKeyShortcutEvent(event)) {
4345 return FINISH_HANDLED;
4346 }
....
4428 }
4430 private int processPointerEvent(QueuedInputEvent q) {
4431 final MotionEvent event = (MotionEvent)q.mEvent;
...
4438 boolean handled = eventTarget.dispatchPointerEvent(event);
...
4447 return handled ? FINISH_HANDLED : FORWARD;
4448 }
2,当凌乱的时候,就画画图。
2.1 类图
重要参与者们以及他们的部分内部类
2.2 简易序列图
KeyEvent的大致调用图,TouchEvent也基本一致。
3 总结
本篇文章简易分析了一下事件在framework的java层流转的流程,我对事件在这个层面的流转形成了一个初步的认识。
当然这太简易了,因为其中的细节包括event的消息队列管理,不同事件(按键,触摸,轨迹球)的处理,输入法相关等等,实在是太多了。后面遇到细节的问题,再来补充这些细节设计的目的。
后面有时间再来往前追溯,就是事件从InputManager到NativeInputEventReceiver的过程。
编写文章是为了自我总结,欢迎批评指正。
4 呜谢
ViewRootImpl的独白,我不是一个View(布局篇)
Android系统MotionEvent处理Receiver端基本原理总结