【android Framework 探究】事件分发

概述

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 呜谢

View·InputEvent事件投递源码分析(一)

Android Input系统1 输入系统概述

ViewRootImpl的独白,我不是一个View(布局篇)

Android系统MotionEvent处理Receiver端基本原理总结

android framework层input事件接收和派发

从点击屏幕到事件处理的事件分发源码流程

猜你喜欢

转载自blog.csdn.net/lucky_tom/article/details/120893529
今日推荐