touch事件是怎么到activity的

Touch 事件到底是怎么到activity的?

引言

我们分析touch事件都是说从activity-》view,那么事件是怎么到activity的?

ViewRootImpl

在View绘制中经常提到ViewRootImpl,从测量布局到绘制都是从它开始的,而事件也是从它真正的开始,具体这部分的代码涉及比较多,我没有完全确定,目前最清晰的线开始点是这个,如果打架对这部分有疑问,或者别的,或者更好的理解,欢迎大家拍砖。
事件开始: 这个地方有疑问,可能不是这里,事件入口怀疑是在: mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());等后续再看看

public void dispatchInputEvent(InputEvent event) {
       dispatchInputEvent(event, null);
   }

   public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
       SomeArgs args = SomeArgs.obtain();
       args.arg1 = event;
       args.arg2 = receiver;
       Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
       msg.setAsynchronous(true);
       mHandler.sendMessage(msg);
   }

这两个方法一看就是处理事件的,主要工作就是变换线程。

case MSG_DISPATCH_INPUT_EVENT: {//分发事件
               SomeArgs args = (SomeArgs)msg.obj;
               InputEvent event = (InputEvent)args.arg1;
               InputEventReceiver receiver = (InputEventReceiver)args.arg2;
               enqueueInputEvent(event, receiver, 0, true);
               args.recycle();
           } break;

然后就看enqueueInputEvent(event, receiver, 0, true);这里要注意下最后两个0和true

 void enqueueInputEvent(InputEvent event,
           InputEventReceiver receiver, int flags, boolean processImmediately) {
       adjustInputEventForCompatibility(event);
       QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);//生成处理事件
       加入队列
       if (processImmediately) {//true,马上处理队列
           doProcessInputEvents();
       } else {
           scheduleProcessInputEvents();//给handler
       }

我们直接进入事件处理

void doProcessInputEvents() {
       // Deliver all pending input events in the queue.
       while (mPendingInputEventHead != null) {
           QueuedInputEvent q = mPendingInputEventHead;
           mPendingInputEventHead = q.mNext;
           if (mPendingInputEventHead == null) {
               mPendingInputEventTail = null;
           }
           q.mNext = null;

           mPendingInputEventCount -= 1;
           Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
                   mPendingInputEventCount);

           long eventTime = q.mEvent.getEventTimeNano();
           long oldestEventTime = eventTime;
           if (q.mEvent instanceof MotionEvent) {
               MotionEvent me = (MotionEvent)q.mEvent;
               if (me.getHistorySize() > 0) {
                   oldestEventTime = me.getHistoricalEventTimeNano(0);
               }
           }
           mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);

           deliverInputEvent(q);//最重要的就是它,其他的先不用管
       }

       // We are done processing all input events that we can process right now
       // so we can clear the pending flag immediately.
       if (mProcessInputEventsScheduled) {
           mProcessInputEventsScheduled = false;
           mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
       }
   }

deliverInputEvent 处理事件

   private void deliverInputEvent(QueuedInputEvent q) {
      Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
              q.mEvent.getSequenceNumber());
      if (mInputEventConsistencyVerifier != null) {
          mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
      }

      InputStage stage;
      if (q.shouldSendToSynthesizer()) {
          stage = mSyntheticInputStage;
      } else {
          stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
      }

      if (stage != null) {
          stage.deliver(q);
      } else {
          finishInputEvent(q);
      }
  }

InputStage 这个类很有意思。InputStage是一个实现处理输入事件责任的阶段,它是一个基类,也就是说InputStage提供一系列处理输入事件的方法,也可以转发给其他事件处理,而具体的处理则是看它的实现类。每种InputStage可以处理一定的事件类型,比如AsyncInputStage、ViewPreImeInputStage、ViewPostImeInputStage等。当一个InputEvent到来时,ViewRootImpl会寻找合适它的InputStage来处理
主要是是事件里面的:shouldSendToSynthesizer和shouldSkipIme方法。
这两个方法都与flags相关,这里回到QueuedInputEvent,看它到底是怎么生成的?

 private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
            InputEventReceiver receiver, int flags) {
        QueuedInputEvent q = mQueuedInputEventPool;
        if (q != null) {
            mQueuedInputEventPoolSize -= 1;
            mQueuedInputEventPool = q.mNext;
            q.mNext = null;
        } else {
            q = new QueuedInputEvent();
        }

        q.mEvent = event;
        q.mReceiver = receiver;
        q.mFlags = flags;
        return q;
    }

flags就是上面的0.
所以shouldSendToSynthesizer是false

public boolean shouldSkipIme() {
            if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
                return true;
            }
            return mEvent instanceof MotionEvent
                    && (mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)//
                        || mEvent.isFromSource(InputDevice.SOURCE_ROTARY_ENCODER));这个地方是true touch事件,主要是SOURCE_CLASS_POINTER
        }

所以stage是mFirstPostImeInputStage,看它的初始化。

InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
                        "aq:native-post-ime:" + counterSuffix);
InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
mFirstPostImeInputStage = earlyPostImeStage;               

进入到deliver方法里面,其实里面就是如果自己处理就处理,不处理就继续传递给next处理,next就是InputStage初始化的第一个参数。

/**
         * Delivers an event to be processed.
         */
        public final void deliver(QueuedInputEvent q) {
            if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
                forward(q);
            } else if (shouldDropInputEvent(q)) {
                finish(q, false);
            } else {
                apply(q, onProcess(q));//走这里
            }
        }

最后到这里

private int processPointerEvent(QueuedInputEvent q) {
            final MotionEvent event = (MotionEvent)q.mEvent;

            mAttachInfo.mUnbufferedDispatchRequested = false;
            mAttachInfo.mHandlingPointerEvent = true;
            boolean handled = mView.dispatchPointerEvent(event);//眼熟不?布尔值最后是不是跟touch有点像?
            maybeUpdatePointerIcon(event);
            maybeUpdateTooltip(event);
            mAttachInfo.mHandlingPointerEvent = false;
            if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
                mUnbufferedInputDispatch = true;
                if (mConsumeBatchedInputScheduled) {
                    scheduleConsumeBatchedInputImmediately();
                }
            }
            return handled ? FINISH_HANDLED : FORWARD;//这里就是apply的第二个参数,告诉要干啥
        }

mView.dispatchPointerEvent(event);//眼熟不?布尔值最后是不是跟touch有点像?
这个view是什么呢?DecorView,是不是回来了?
DecorView的dispatchTouchEvent

   @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);
    }

Window.Callback 是什么呢?Actiivty!
在Activity的attach方法中

mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
 mWindow.setCallback(this);

所以事件就到了activity。剩下的就是

activity----->
public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();
        }
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }

 class PhoneWindow---->
 @Override
    public boolean superDispatchTouchEvent(MotionEvent event) {
        return mDecor.superDispatchTouchEvent(event);
    }
    回到DecorView-》superDispatchTouchEvent//名字取得我是。。。
    public boolean superDispatchKeyEvent(KeyEvent event) {
        // Give priority to closing action modes if applicable.
        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
            final int action = event.getAction();
            // Back cancels action modes first.
            if (mPrimaryActionMode != null) {
                if (action == KeyEvent.ACTION_UP) {
                    mPrimaryActionMode.finish();
                }
                return true;
            }
        }

        return super.dispatchKeyEvent(event);//viewGroup
    }
    

事件完美处理。
看代码是很累,但是很有意思吧,把事情连起来,真好玩。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值