Andriod事情分发的事情从何而来(一)

事情分发一直以来都是一个android常识的要点。从使用开发角度和用户的交互便是在处理事情。

Activity的事情分发

事情分发一般情况都会讲view的分发进程,他的进程缩略起来就可以这样表明。

public boolean diapatchTouchEvent(MotionEvent ev) {
  boolean consume = false;
  if (onInterceptTouchEvent(ev)) {
    consume = onTouchEvent(ev);
   } else {
    consume = child.dispatchTouchEvent(ev);
   }
  return consume;
}

这儿就有一个问题,最早的事情是从哪里来的。根据Android的视图模型知道最外层的view便是DecorView ,而它的外面是一个PhoneWindow。所以开始的事情便是从PhoneWindow进入了view的事情分发,而PhoneWindow的事情又是Activity中来的.

//frameworks/base/core/java/android/app/Activity.java
public boolean dispatchTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
      onUserInteraction();
     }
    if (getWindow().superDispatchTouchEvent(ev)) {//这儿获取的PhoneWindow
      return true;
     }
    return onTouchEvent(ev);
   }

那么问题又来了,activity的事情是哪里来的呢。

ViewRootImpl事情分发

了解Android的Window创立流程的话就知道ViewRootImpl是一切view的最顶层。也是ViewRootImpl在setView中完成了View和WindowManager之间的交互。这个办法里有一个在Window创立流程的时分没有关注的InputChannel,事情真实的来源便是它,在

 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
      int userId) {
    synchronized (this) {
      if (mView == null) {
        mView = view;
        .........
        InputChannel inputChannel = null;//创立InputChannel
        if ((mWindowAttributes.inputFeatures
            & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
          inputChannel = new InputChannel();
         }
       
          res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
              getHostVisibility(), mDisplay.getDisplayId(), userId,
              mInsetsController.getRequestedVisibilities(), inputChannel, mTempInsets,mTempControls, attachedFrame, sizeCompatScale);//将InputChannel传给WMS
        if (inputChannel != null) {
          if (mInputQueueCallback != null) {
            mInputQueue = new InputQueue();
            mInputQueueCallback.onInputQueueCreated(mInputQueue);
           }
          mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
              Looper.myLooper());//创立mInputEventReceiver
         }
​
       //这儿创立了各种事情处理器
        // Set up the input pipeline.
        CharSequence counterSuffix = attrs.getTitle();
        mSyntheticInputStage = new SyntheticInputStage();
        InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
        InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
            "aq:native-post-ime:" + counterSuffix);
        InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
        InputStage imeStage = new ImeInputStage(earlyPostImeStage,
            "aq:ime:" + counterSuffix);
        InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
        InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
            "aq:native-pre-ime:" + counterSuffix);mFirstInputStage = nativePreImeStage;
        mFirstPostImeInputStage = earlyPostImeStage;
        mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
​
        AnimationHandler.requestAnimatorsEnabled(mAppVisible, this);
       }
     }
   }

从姓名也能猜出mInputEventReceiver便是接纳事情的对象了,这是一个ViewRootImpl的内部类看下它的完成。

 final class WindowInputEventReceiver extends InputEventReceiver {
    public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
      super(inputChannel, looper);
     }
​
    @Override
    public void onInputEvent(InputEvent event) {//经过姓名就知道这应该是事情接纳的回调
      List<InputEvent> processedEvents;
      try {
        processedEvents =
          mInputCompatProcessor.processInputEventForCompatibility(event);
       } finally {
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
       }
      if (processedEvents != null) {
        if (processedEvents.isEmpty()) {
          // InputEvent consumed by mInputCompatProcessor
          finishInputEvent(event, true);
         } else {
          for (int i = 0; i < processedEvents.size(); i++) {
            enqueueInputEvent(
                processedEvents.get(i), this,
                QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY, true);
           }
         }
       } else {
        enqueueInputEvent(event, this, 0, true);
       }
     }
  .......
 }

如果processedEvents不为空都是调用了enqueueInputEvent,否则就直接调用finishInputEvent。

 void enqueueInputEvent(InputEvent event,
      InputEventReceiver receiver, int flags, boolean processImmediately) {
    QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
        //这儿做了区别是触摸事情仍是按键事情
    if (event instanceof MotionEvent) {
      MotionEvent me = (MotionEvent) event;
     } else if (event instanceof KeyEvent) {
      KeyEvent ke = (KeyEvent) event;
     }
    
    QueuedInputEvent last = mPendingInputEventTail;
    if (last == null) {
      mPendingInputEventHead = q;
      mPendingInputEventTail = q;
     } else {
      last.mNext = q;
      mPendingInputEventTail = q;
     }
    mPendingInputEventCount += 1;
    if (processImmediately) {
      doProcessInputEvents();
     } else {
      scheduleProcessInputEvents();
     }
   }
​
​
  private void scheduleProcessInputEvents() {
    if (!mProcessInputEventsScheduled) {
      mProcessInputEventsScheduled = true;
      Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
      msg.setAsynchronous(true);
      mHandler.sendMessage(msg);
     }
   }
​
​
 private void handleMessageImpl(Message msg) {
      switch (msg.what) {
        case MSG_PROCESS_INPUT_EVENTS:
          mProcessInputEventsScheduled = false;
          doProcessInputEvents();
       }
  }

这儿判别了是否要当即消费,如果当即消费doProcessInputEvents,否则调用scheduleProcessInputEvents。而scheduleProcessInputEvents很简单便是handle发送了一个异步音讯。最后handle执行的时分仍是会调用到doProcessInputEvents。所以就来详细看下doProcessInputEvents。

  void doProcessInputEvents() {
    // Deliver all pending input events in the queue.
    while (mPendingInputEventHead != null) {//循环获取InputEvent并处理
      QueuedInputEvent q = mPendingInputEventHead;
      mPendingInputEventHead = q.mNext;
      if (mPendingInputEventHead == null) {
        mPendingInputEventTail = null;
       }
      q.mNext = null;
​
      mPendingInputEventCount -= 1;
      mViewFrameInfo.setInputEvent(mInputEventAssigner.processEvent(q.mEvent));
      deliverInputEvent(q);
     }
​
      //移除异步音讯
    if (mProcessInputEventsScheduled) {
      mProcessInputEventsScheduled = false;
      mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
     }
   }
​

可以看到真实的处理都是deliverInputEvent来处理。

​
​
 private void deliverInputEvent(QueuedInputEvent q) {
​
    try {
      if (mInputEventConsistencyVerifier != null) {
      InputStage stage;//在ViewRootImpl的setView中初始化的处理器
      if (q.shouldSendToSynthesizer()) {
        stage = mSyntheticInputStage;
       } else {
        stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
       }
​
      if (q.mEvent instanceof KeyEvent) {
        try {
          mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
         } finally {
          Trace.traceEnd(Trace.TRACE_TAG_VIEW);
         }
       }
      if (stage != null) {
        handleWindowFocusChanged();
        stage.deliver(q);
       } else {
        finishInputEvent(q);
       }
     } finally {
     }
   }

在deliverInputEvent中出现了stage,这便是在setView初始化的那些处理器,处理经过stage.deliver(q)来完成。 InputStage 仍是ViewRootImpl的一个内部类。

 abstract class InputStage {
    private final InputStage mNext;
    protected static final int FORWARD = 0;
    protected static final int FINISH_HANDLED = 1;
    protected static final int FINISH_NOT_HANDLED = 2;
    private String mTracePrefix;
​
    public InputStage(InputStage next) {
      mNext = next;
     }
​
    public final void deliver(QueuedInputEvent q) {
     //分发事情
      if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
        forward(q);
       } else if (shouldDropInputEvent(q)) {
        finish(q, false);
       } else {
        traceEvent(q, Trace.TRACE_TAG_VIEW);
        final int result;
        try {
          result = onProcess(q);
         } finally {
          Trace.traceEnd(Trace.TRACE_TAG_VIEW);
         }
        apply(q, result);
       }
     }
       //处理事情由子类改写
    protected int onProcess(QueuedInputEvent q) {
      return FORWARD;
     }
    protected void finish(QueuedInputEvent q, boolean handled) {
      q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
      if (handled) {
        q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
       }
      forward(q);
     }
​
    protected void forward(QueuedInputEvent q) {
      onDeliverToNext(q);
     }
​
    protected void onDeliverToNext(QueuedInputEvent q) {
     //向后一个 InputStage 传递事情
      if (mNext != null) {
        mNext.deliver(q);
       } else {
        finishInputEvent(q);
       }
     }
   }
​

了解okhttp的话很容易就发现这儿也是一个职责链形式。从setView中 InputStage 子类的初始化也能看到,其中和view相关的是ViewPostImeInputStage。

 final class ViewPostImeInputStage extends InputStage {
    public ViewPostImeInputStage(InputStage next) {
      super(next);
     }
​
    @Override
    protected int onProcess(QueuedInputEvent q) {
      if (q.mEvent instanceof KeyEvent) {
        return processKeyEvent(q);
       } else {
        final int source = q.mEvent.getSource();
       //判别事情类型,触摸事情会进入processPointerEvent
        if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
          return processPointerEvent(q);
         } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
          return processTrackballEvent(q);
         } else {
          return processGenericMotionEvent(q);
         }
       }
     }
    private int processPointerEvent(QueuedInputEvent q) {
      final MotionEvent event = (MotionEvent)q.mEvent;
      mHandwritingInitiator.onTouchEvent(event);mAttachInfo.mUnbufferedDispatchRequested = false;
      mAttachInfo.mHandlingPointerEvent = true;
     //经过mView的dispatchPointerEvent来分发事情
      boolean handled = mView.dispatchPointerEvent(event);
      maybeUpdatePointerIcon(event);
      maybeUpdateTooltip(event);
      mAttachInfo.mHandlingPointerEvent = false;
      if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
        mUnbufferedInputDispatch = true;
        if (mConsumeBatchedInputScheduled) {
          scheduleConsumeBatchedInputImmediately();
         }
       }
      return handled ? FINISH_HANDLED : FORWARD;
     }
​

ViewRootImpl的事情就交给mView来继续分发了,这儿mView是DecorView,也是在setView中传进来的。

DecorView事情处理

 
//frameworks/base/core/java/android/view/View.java
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
  public final boolean dispatchPointerEvent(MotionEvent event) {
    if (event.isTouchEvent()) {
      return dispatchTouchEvent(event);
     } else {
      return dispatchGenericMotionEvent(event);
     }
   }
//frameworks/base/core/java/com/android/internal/policy/DecorView.java
 @Override
  public boolean dispatchTouchEvent(MotionEvent ev) {
    final Window.Callback cb = mWindow.getCallback();
    return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
        ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
   }
​

这儿经过dispatchTouchEvent将事情交给了Window.Callback,而这儿的Window.Callback便是Activity,兜兜转转总算回到了Activity的dispatchTouchEvent中。

经过这个流程可以知道,事情的流程是WMS->ViewRootImpl->DecorView->Activity->PhoneWindow->DecorView,这儿有一个疑问便是为什么不直接从DecorView开始分发。我猜想是为了方便在使用层重写Activity中的onTouch来消费没有view处理的事情。

现在还有一个疑问是WMS的事情是怎样来的,这个留着后续再分析。