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
}
事件完美处理。
看代码是很累,但是很有意思吧,把事情连起来,真好玩。