基于Android 9 分析
框架层可见的点击事件从哪里来? 所有的事件都是由InputEventReceiver 先接受再分发出来的,
1 2 3 4 5 6 @SuppressWarnings ("unused" )private void dispatchInputEvent (int seq, InputEvent event, int displayId) { mSeqMap.put(event.getSequenceNumber(), seq); onInputEvent(event, displayId); }
那native code 又是怎么才会调上来的呢? 那就是在 InputEventReceiver 初始化的时候,需要注册。就是在 nativeInit 方法里面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public InputEventReceiver (InputChannel inputChannel, Looper looper) { if (inputChannel == null ) { throw new IllegalArgumentException("inputChannel must not be null" ); } if (looper == null ) { throw new IllegalArgumentException("looper must not be null" ); } mInputChannel = inputChannel; mMessageQueue = looper.getQueue(); mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this ), inputChannel, mMessageQueue); mCloseGuard.open("dispose" ); }
InputChannel
An input channel specifies the file descriptors used to send input events to a window in another process. It is Parcelable so that it can be sent to the process that is to receive events. Only one thread should be reading from an InputChannel at a time.
输入通道指定用于在另一个进程中将输入事件发送到窗口的文件描述符。 它是Parcelable,因此可以将其发送到要接收事件的进程。 一次只能一个线程从InputChannel读取。
1 2 private static native long nativeInit (WeakReference<InputEventReceiver> receiver, InputChannel inputChannel, MessageQueue messageQueue) ;
在我们启动App的时候,最先由AMS跨进程传输的一个ClientTransaction,客户端进程ApplicationThread接收,然后发送到主线程ActivityThread,最后由TransactionExecutor统一解析。AMS封装并传输ClientTransaction,统一接口;客户端进程接收ClientTransaction并使用TransactionExecutor解析AMS的请求,再根据ActivityLifecycleItem执行不同的代码。Activity的生命周期就是 transaction.getLifecycleStateRequest() 获取的,然后再执行响应的生命周期回调。
调用栈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 <init>(InputChannel, Looper):60 , InputEventReceiver (android.view)<init>(ViewRootImpl, InputChannel, Looper):7190 , ViewRootImpl$WindowInputEventReceiver (android.view) setView(View, WindowManager$LayoutParams, View):847 , ViewRootImpl (android.view) addView(View, ViewGroup$LayoutParams, Display, Window):356 , WindowManagerGlobal (android.view) addView(View, ViewGroup$LayoutParams):93 , WindowManagerImpl (android.view) handleResumeActivity(IBinder, boolean , boolean , String):3868 , ActivityThread (android.app) execute(ClientTransactionHandler, IBinder,PendingTransactionActions):51 , ResumeActivityItem (android.app.servertransaction) executeLifecycleState(ClientTransaction):145 , TransactionExecutor (android.app.servertransaction) execute(ClientTransaction):70 , TransactionExecutor (android.app.servertransaction) handleMessage(Message):1808 , ActivityThread$H (android.app) dispatchMessage(Message):106 , Handler (android.os) loop():193 , Looper (android.os) main(String[]):6669 , ActivityThread (android.app) invoke(Object, Object[]):-1 , Method (java.lang.reflect) run():493 , RuntimeInit$MethodAndArgsCaller (com.android.internal.os) main(String[]):858 , ZygoteInit (com.android.internal.os)
我们可以看到 在 android.view.ViewRootImpl#setView当中调用了,这个looper就是主线程的looepr了。这个InputChannel 实际上指向我们自己写的MainActivity (client)
1 2 mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper());
再来看一 nativeInit 又做了什么呢? 在NativeInputEventReceiver的nativeInit方法中,创建了NativeInputEventReceiver对象,并调用它的initialize方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 static jint nativeInit (JNIEnv* env, jclass clazz, jobject receiverWeak, jobject inputChannelObj, jobject messageQueueObj) { ... sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env, receiverWeak, inputChannel, messageQueue); status_t status = receiver->initialize(); ... } status_t NativeInputEventReceiver::initialize () { setFdEvents(ALOOPER_EVENT_INPUT); return OK; }
mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
实际上就把JAVA层的Looper关联ALOOPER_EVENT_INPUT
1 2 3 4 5 6 7 8 9 10 11 void NativeInputEventReceiver::setFdEvents (int events) { if (mFdEvents != events) { mFdEvents = events; int fd = mInputConsumer.getChannel()->getFd(); if (events) { mMessageQueue->getLooper()->addFd(fd, 0 , events, this , NULL ); } else { mMessageQueue->getLooper()->removeFd(fd); } } }
fd,fd即inputChannel的socket fd,Looper会侦测该fd的状态
events,即传入的ALOOPER_EVENT_INPUT,只有fd的状态是INPUT的时候才会触发调用LooperCallback中的handleEvent方法
this,即NativeInputEventReceiver,当fd状态为Input时,NativeInputEventReceiver中的handleEvent方法会被调用
在consumeEvents内,我们能看到调用了InputConsume::consume来接收InputDispatcher发送过来的事件
1 2 3 4 5 6 7 status_t NativeInputEventReceiver::consumeEvents (JNIEnv* env, bool consumeBatches, nsecs_t frameTime, bool * outConsumedBatch) { for (;;) { status_t status = mInputConsumer.consume(&mInputEventFactory, consumeBatches, frameTime, &seq, &inputEvent); } }
最终回调到 java 层的 InputEventReceiver#dispatchInputEvent 。
1 2 env->CallVoidMethod(receiverObj.get (), gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
通过上述的JNI调用,会调用到WindowInputEventReceiver的dispatchInputEvent方法,不过由于WindowInputEventReceiver并没有自己实现这个方法,因此会调用父类InputEventReceiver::dispatchInputEvent,内部会真正调用到android.view.ViewRootImpl.WindowInputEventReceiver#onInputEvent
接下来就是JAVA层,一层层分发事件了
android.view.ViewRootImpl.WindowInputEventReceiver#onInputEvent
1 2 3 public void onInputEvent (InputEvent event, int displayId) { enqueueInputEvent(event, this , 0 , true ); }
android.view.ViewRootImpl#enqueueInputEvent(android.view.InputEvent, android.view.InputEventReceiver, int, boolean)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 void enqueueInputEvent (InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately) { adjustInputEventForCompatibility(event); QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags); QueuedInputEvent last = mPendingInputEventTail; if (last == null ) { mPendingInputEventHead = q; mPendingInputEventTail = q; } else { last.mNext = q; mPendingInputEventTail = q; } mPendingInputEventCount += 1 ; Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName, mPendingInputEventCount); if (processImmediately) { doProcessInputEvents(); } else { scheduleProcessInputEvents(); } }
从 enqueueInputEvent(event, this, 0, true) 看 ,这里的事件是processImmediately = true的,所以进一步再追一下 doProcessInputEvents()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 void doProcessInputEvents () { 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); } if (mProcessInputEventsScheduled) { mProcessInputEventsScheduled = false ; mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS); } }
接下来再继续追一下 android.view.ViewRootImpl#deliverInputEvent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 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 (q.mEvent instanceof KeyEvent) { mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent); } if (stage != null ) { handleWindowFocusChanged(); stage.deliver(q); } else { finishInputEvent(q); } }
deliverInputEvent先判断将事件派发到那个InputStage,然后调用该InputState的deliver方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public void setView (View view, WindowManager.LayoutParams attrs, View panelParentView) { ... 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; ... }
InputStage 是在setView()的时候创建的,也就是在Activity的onResume()
通过一路的 forward deliver ,最后走到apply 的 onProcess 方法中去。也就是 android.view.ViewRootImpl.ViewPostImeInputStage#onProcess
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 protected int onProcess (QueuedInputEvent q) { if (q.mEvent instanceof KeyEvent) { return processKeyEvent(q); } else { final int source = q.mEvent.getSource(); 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); } } }
那么再来看下一
android.view.ViewRootImpl.ViewPostImeInputStage#processPointerEvent 里面又是怎么发的?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 private int processPointerEvent (QueuedInputEvent q) { final MotionEvent event = (MotionEvent)q.mEvent; mAttachInfo.mUnbufferedDispatchRequested = false ; mAttachInfo.mHandlingPointerEvent = true ; 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; }
当调用到 DecorView 的 dispatchPointerEvent ,实际上是 android.view.View#dispatchPointerEvent ,接下来的问题实际上就是 view的事件分发了?
1 2 3 4 5 6 7 8 9 public final boolean dispatchPointerEvent (MotionEvent event) { if (event.isTouchEvent()) { return dispatchTouchEvent(event); } else { return dispatchGenericMotionEvent(event); } }
转接到
com.android.internal.policy.DecorView#dispatchTouchEvent
1 2 3 4 5 6 7 8 9 public boolean dispatchTouchEvent (MotionEvent ev) { final Window.Callback cb = mWindow.getCallback(); return cb != null && !mWindow.isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev) : super .dispatchTouchEvent(ev); }
最后cb.dispatchTouchEvent(ev) 就相当于 走入到了
android.app.-Activity#dispatchTouchEvent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public boolean dispatchTouchEvent (MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { onUserInteraction(); } if (getWindow().superDispatchTouchEvent(ev)) { return true ; } return onTouchEvent(ev); }
Activity 的 getWindow() 就是 android.app.Activity#attach中的mWindow ,也就是 PhoneWindow。
com.android.internal.policy.PhoneWindow#superDispatchTouchEvent
1 2 3 4 5 @Override public boolean superDispatchTouchEvent (MotionEvent event) { return mDecor.superDispatchTouchEvent(event); }
从上面的标记1,2,3 可以看到,首先事件从 android.view.ViewRootImpl.ViewPostImeInputStage#processPointerEvent 发到 DecorView ,DecorView 再分发事件的时候,通过 Window 获取callback 拿到 Activity ,转交给Activity 去发送,但是Activity又通过 getWindow,又把事件转交给Window ,Window 最后又通过mDecor.superDispatchTouchEvent(event) 转交给 了DecorView。搞半天?最后还是回到 android.view.ViewRootImpl.ViewPostImeInputStage#processPointerEvent 的 mView.dispatchPointerEvent(event)中?
显然不是 第一次调用的是 DecorView.dispatchPointerEvent(event) ,第二次回到 DecorView是调用的 DecorView.superDispatchTouchEvent(event);也就调用到 DecorView 的父类 DispatchTouchEvent ,最后也就是 android.view.ViewGroup#dispatchTouchEvent的了。
一小段调用栈
1 2 3 4 5 6 7 8 9 --- dispatchTouchEvent(MotionEvent):2543 , ViewGroup (android.view) superDispatchTouchEvent(MotionEvent):440 , DecorView (com.android.internal.policy) superDispatchTouchEvent(MotionEvent):1830 , PhoneWindow (com.android.internal.policy) dispatchTouchEvent(MotionEvent):3400 , Activity (android.app) dispatchTouchEvent(MotionEvent):398 , DecorView (com.android.internal.policy) dispatchPointerEvent(MotionEvent):12752 , View (android.view) processPointerEvent(ViewRootImpl$QueuedInputEvent):5106 ,、 ---
为什么在InputStage.processPointerEvent()中不直接把事件传递给Activity,而是这样来回绕一圈。这样DecorView -> Activity -> PhoneWindow -> DecorView的来回绕一圈不是很折腾吗?
首先,为了解耦,ViewRootImpl并不知道有Activity这种东西存在!不知道!它只是持有了DecorView。所以,想要直接把触摸事件送到Activity.dispatchTouchEvent() 是不行的。
那么,既然触摸事件已经到了Activity.dispatchTouchEvent()中了,为什么不直接分发给DecorView ,而是要通过PhoneWindow 来间接发送呢?因为Activity 不知道有DecorView 这种奇怪的东西存在啊!不知道!但是,Activity持有PhoneWindow ,而PhoneWindow当然知道自己的窗口里有些什么了,所以能够把事件派发给DecorView 。你看,在Android中,Activity并不知道自己的Window中有些什么,这样耦合性就很低了。我们换一个Window试试?不管Window里面的内容如何,只要Window任然符合Activity制定的标准,那么它就能在Activity中很好的工作。这就是解耦所带来的扩展性的好处。
作者:CoorChice 链接:https://www.jianshu.com/p/b7cef3b3e703 来源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
ViewGroup 的事件分发流程? 首先分清楚 3个方法
dispatchTouchEvent() 分发器,决定事件怎么分发,会先询问onInterceptTouchEvent(),如果拦截了 进一步到 自己的 onTouchEvent() 中去。如果没有拦截,转发到子view的dispatchTouchEvent()
onInterceptTouchEvent() 拦截器 是ViewGroup特有的方法,可以判断和拦截要不要将事件下发到子view去处理。
onTouchEvent() 处理器。最后的一个子view 收到事件将会直接由【分发器】分发到【处理器】中。如果处理了返回true,如果不处理返回false,那么事件将传递到它的父级的【处理器】中。
不管个层级的【处理器】,如果处理事件返回true,一次触摸事件就结束了。如果不处理事件,返回false,就是事件还没有被消费,就会传送到上一级的【处理器】中。最终,如果DecorView的【处理器】也不打算处理事件,那么事件将会被发送到Activity的【处理器】中处理。
说白了,就是先交给子view优先消费,消费不了,返回了,我再消费。
那么ViewGroup dispatchTouchEvent()又是怎么把事件发到child view中去的呢?
android.view.ViewGroup#dispatchTouchEvent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 final ArrayList<View> preorderedList = buildTouchDispatchChildList();final boolean customOrder = preorderedList == null && isChildrenDrawingOrderEnabled(); final View[] children = mChildren;for (int i = childrenCount - 1 ; i >= 0 ; i--) { final int childIndex = getAndVerifyPreorderedIndex( childrenCount, i, customOrder); final View child = getAndVerifyPreorderedView( preorderedList, children, childIndex); if (childWithAccessibilityFocus != null ) { if (childWithAccessibilityFocus != child) { continue ; } childWithAccessibilityFocus = null ; i = childrenCount - 1 ; } if (!canViewReceivePointerEvents(child) || !isTransformedTouchPointInView(x, y, child, null )) { ev.setTargetAccessibilityFocus(false ); continue ; }
最后再子view的 android.view.View#onTouchEvent中,包装成一个 mPerformClick ,最后通过 mHandler.post(action) 把这个 action 发到 主线程的looper 里面去处理了,然后looepr 处理消息,调用action ,就是我们set的OnClickListener里面去了。
android.os.Handler#dispatchMessage
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public void dispatchMessage (Message msg) { if (msg.callback != null ) { handleCallback(msg); } else { if (mCallback != null ) { if (mCallback.handleMessage(msg)) { return ; } } handleMessage(msg); } }
最后 调到 message.callback.run();
然后 在run() 调用 performClick() 中的 mOnClickListener.onClick(this);
最后我们 就开始我们的OnClick 逻辑了
总结 最后一张大图
感谢 [Android] 输入系统(二)] https://www.cnblogs.com/TaigaCon/p/4750349.html
作者:CoorChice 链接:https://www.jianshu.com/p/b7cef3b3e703 来源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。