溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Android4.4   Input模塊筆記

發(fā)布時間:2020-07-20 17:02:32 來源:網(wǎng)絡(luò) 閱讀:446 作者:yangxiaoming123 欄目:移動開發(fā)

InputReaderEventHub中獲取輸入事件,包含觸摸屏事件、物理按鍵事件等,然后轉(zhuǎn)交給InputDispatcher線程,InputDispatcher經(jīng)過篩選,過濾輸入事件。對于觸摸事件通過調(diào)用findTouchedWindowTargetsLocked()函數(shù)找到合適的InputTarget,然后通過dispatchEventLocked()->prepareDispatchCycleLocked()->enqueueDispatchEntriesLocked()->enqueueDispatchEntryLocked()->  connection->outboundQueue.enqueueAtTail(dispatchEntry)添加到與InputTarget一一對應(yīng)的connection中的一個隊列中。如果之前該隊列無數(shù)據(jù),并且當(dāng)前觸摸事件已成功加入該隊列,則繼續(xù)調(diào)用startDispatchCycleLocked()函數(shù)進行分發(fā)處理。在startDispatchCycleLocked()中,有一個while循環(huán),該循環(huán)從connection->outboundQueue隊列中取出輸入事件,如果該輸入事件是按鍵(key)事件,則調(diào)用connection->inputPublisher.publishKeyEvent()函數(shù),如果是觸摸事件則調(diào)用connection->inputPublisher.publishMotionEvent()。publishKeyEvent()publishMotionEvent()都是調(diào)用mChannel->sendMessage()將輸入事件發(fā)送出去。mChannel是一個C++InputChannel對象,該對象的賦值過程如下:registerInputChannel()->new Connection->Connection()構(gòu)造函數(shù)->InputPublisher()構(gòu)造函數(shù)。事實上,在registerInputChannel()被調(diào)用之前,ViewRootImple在增加一個窗口時調(diào)用ViewRootImpl.setView()->mWindowSession.addToDisplay()-WindowManagerService.addWindow(),在addWindow()中會創(chuàng)建一對InputChannelNativie層),實際上是創(chuàng)建一對Socket,服務(wù)端InputChanelWMS注冊到InputDispatcher中,客戶端InputChannel被返回給ViewRootImplViewRootImpl將客戶端InputChannel作為參數(shù)new一個InputEventReceiver對象,在InputEventReceiver()構(gòu)造函數(shù)中繼續(xù)調(diào)用nativeInit()函數(shù)來創(chuàng)建一個native層的NativeInputEventReceiver對象,前面創(chuàng)建的客戶端InputChannel會保存在該對象中。

總結(jié):WMS會調(diào)用native層接口創(chuàng)建一對套接字,服務(wù)端保存在InputDispatcher中,客戶端保存在NativeInputEventReceiver中(android_view_inputEventReceiver.cpp)。

很容易想到輸入事件是從InputDispatcher流向NativeInputEventReceiver中。在創(chuàng)建一個native層的NativeInputEventReceiver對象后會立即調(diào)用NativeInputEventReceiver->initialize(),該函數(shù)調(diào)用mMessageQueue->getLooper()->addFd(fd,0, events, this, NULL)將客戶端socket句柄添加到Looper的輪詢隊列中,參數(shù)this指向NativeInputEventReceiver本身,意味著只要服務(wù)端InputDispatcher發(fā)送輸入事件,客戶端收到這個事件,就調(diào)用NativeInputEventReceiver的某個函數(shù),具體調(diào)用哪個函數(shù),自然是NativeInputEventReceiver實現(xiàn)了LooperCallback的接口函數(shù)handleEvent()。但此時收到的事件只是代表socket客戶端有事件來,并沒有把具體的事件讀取出來,這點需要注意。

總結(jié):客戶端收到輸入事件,即調(diào)用NativeInputEventReceiver->handleEvent()函數(shù)。

handleEvent()函數(shù)中,繼續(xù)調(diào)用consumeEvents()->mInputConsumer.consume()->mChannel->receiveMessage(&mMsg)將具體輸入事件讀取出來,然后調(diào)用env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.dispatchInputEvent,seq, inputEventObj),可以知道native層讀取輸入事件后,然后會回調(diào)javaInputEventReceiver.java中的dispatchInputEvent()函數(shù)。事實上,

dispatchInputEvent繼續(xù)調(diào)用onInputEvent(event); 此時可能并不調(diào)用InputEventReceiver類中的onInputEvent()方法,而是調(diào)用子類onInputEvent()方法。在 ViewRootImpl中存在WindowInputEventReceiver類型變量 mInputEventReceiver,WindowInputEventReceiver類繼承InputEventReceiver,并實現(xiàn) onInputEvent()方法由此可得出結(jié)論:native層socket客戶端讀取輸入事件,最終調(diào)用InputEventReceiver類子類 的onInputEvent()方法,ViewRootImpl繼承InputEventReceiver,因此 ViewRootImpl.onInputEvent()將被調(diào)用。

總結(jié):對于一般的觸摸屏事件最終處理者是ViewRootImpl類,對于輸入法則處理者是IInputMethodSessionWrapper類,當(dāng)然WMS是不會處理這些輸入事件的。

繼 續(xù)研究ViewRootImpl.onInputEvent()函 數(shù),onInputEvent()->doProcessInputEvents()->deliverInputEvent(),deliverInputEvent() 函數(shù)中會調(diào)用stage.deliver(q),stage是mFirstPostImeInputStage 或 mFirstInputStage,這個兩個InputStage對象在setView中賦值。InputStage類設(shè)計就是責(zé)任鏈模式。因為觸摸事件是要分發(fā)到具體的View上來,所以對于一般的觸摸事件最后是傳遞到ViewPostImeInputStage類中來處理,處理函數(shù)是processPointerEvent(q),這個函數(shù)調(diào)用mView.dispatchPointerEvent(event)將事件分發(fā)出去,mView具體是什么呢?mView其實就是DecorView,每一個窗口有且僅有一個DecorView,且處在最頂層,由于DecorView未重寫dispatchPointerEvent(),所以調(diào)用還是父類View類的dispatchPointerEvent()方法。

[java] view plaincopy

  1. public final boolean dispatchPointerEvent(MotionEvent event) {  

  2.         if (event.isTouchEvent()) {  

  3.             return dispatchTouchEvent(event);  

  4.         } else {  

  5.             return dispatchGenericMotionEvent(event);  

  6.         }  

  7.     }  

該方法繼續(xù)調(diào)用dispatchTouchEvent(event),DecorView重新了該方法:

[java] view plaincopy

  1. @Override  

  2.         public boolean dispatchTouchEvent(MotionEvent ev) {  

  3.             final Callback cb = getCallback();  

  4.             return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev)  

  5.                     : super.dispatchTouchEvent(ev);  

  6.         }  

getCallback() 函數(shù)獲取apk注冊的用于攔截按鍵、觸摸等事件的回調(diào)函數(shù)。一般window不會攔截處理觸摸事件,所以會繼續(xù)調(diào)用 super.dispatchTouchEvent(ev),即父類ViewGroup的dispatchTouchEvent()函數(shù),在該函數(shù)中尋找 到對應(yīng)的View再繼續(xù)調(diào)用dispatchTransformedTouchEvent()

[java] view plaincopy

  1. for (int i = childrenCount - 1; i >= 0; i--) {  

  2.                           final int childIndex = customOrder ?  

  3.                                   getChildDrawingOrder(childrenCount, i) : i;  

  4.                           final View child = children[childIndex];  

  5.                           if (!canViewReceivePointerEvents(child)  

  6.                                   || !isTransformedTouchPointInView(x, y, child, null)) {  

  7.                               continue;  

  8.                           }  

  9.   

  10.                           newTouchTarget = getTouchTarget(child);  

  11.                           if (newTouchTarget != null) {  

  12.                               // Child is already receiving touch within its bounds.  

  13.                               // Give it the new pointer in addition to the ones it is handling.  

  14.                               newTouchTarget.pointerIdBits |= idBitsToAssign;  

  15.                               break;  

  16.                           }  

  17.   

  18.                           resetCancelNextUpFlag(child);  

  19.                           if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {  

  20.                               // Child wants to receive touch within its bounds.  

  21.                               mLastTouchDownTime = ev.getDownTime();  

  22.                               mLastTouchDownIndex = childIndex;  

  23.                               mLastTouchDownX = ev.getX();  

  24.                               mLastTouchDownY = ev.getY();  

  25.                               newTouchTarget = addTouchTarget(child, idBitsToAssign);  

  26.                               alreadyDispatchedToNewTouchTarget = true;  

  27.                               break;  

  28.                           }  

  29.                        

具體的分發(fā)規(guī)則可自行研究代碼。

ViewGroup.dispatchTouchEvent()函數(shù)分析

[html] view plaincopy

  1. @Override  

  2. public boolean dispatchTouchEvent(MotionEvent ev) {  

  3.     if (mInputEventConsistencyVerifier != null) {  

  4.         mInputEventConsistencyVerifier.onTouchEvent(ev, 1);  

  5.     }  

  6.   

  7.     if (DBG_MOTION || DBG_TOUCH) {  

  8.         Xlog.d(TAG, "(ViewGroup)dispatchTouchEvent 1: ev = " + ev + ",mFirstTouchTarget = "  

  9.                 + mFirstTouchTarget + ",this = " + this);  

  10.     }  

  11.   

  12.     boolean handled = false;  

  13.     if (onFilterTouchEventForSecurity(ev)) {  

  14.         final int action = ev.getAction();  

  15.         final int actionMasked = action & MotionEvent.ACTION_MASK;  

  16.   

  17.         // Handle an initial down.  

  18.         if (actionMasked == MotionEvent.ACTION_DOWN) {  

  19.             // Throw away all previous state when starting a new touch gesture.  

  20.             // The framework may have dropped the up or cancel event for the previous gesture  

  21.             // due to an app switch, ANR, or some other state change.  

  22.             cancelAndClearTouchTargets(ev);  

  23.             resetTouchState();  

  24.         }  

  25.   

  26.         // Check for interception.  

  27.         final boolean intercepted;  

  28.         if (actionMasked == MotionEvent.ACTION_DOWN  

  29.                 || mFirstTouchTarget != null) {  

  30.             final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;  

  31.             if (!disallowIntercept) {  

  32.                 intercepted = onInterceptTouchEvent(ev);  

  33.                 /// M : add log to help debugging  

  34.                 if (intercepted == true) {  

  35.                     if (DBG_TOUCH) {  

  36.                         Xlog.d(TAG, "Touch event was intercepted event = " + ev + ",this = " + this);  

  37.                     }  

  38.                 }  

  39.                 ev.setAction(action); // restore action in case it was changed  

  40.             } else {  

  41.                 intercepted = false;  

  42.             }  

  43.         } else {  

  44.             // There are no touch targets and this action is not an initial down  

  45.             // so this view group continues to intercept touches.  

  46.             intercepted = true;  

  47.         }  

  48.   

  49.         // Check for cancelation.  

  50.         final boolean canceled = resetCancelNextUpFlag(this)  

  51.                 || actionMasked == MotionEvent.ACTION_CANCEL;  

  52.   

  53.         // Update list of touch targets for pointer down, if needed.  

  54.         final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;  

  55.         if (DBG_MOTION) {  

  56.             Xlog.d(TAG, "(ViewGroup)dispatchTouchEvent 2: actionMasked = " + actionMasked  

  57.                     + ",intercepted = " + intercepted + ",canceled = " + canceled + ",split = "  

  58.                     + split + ",mChildrenCount = " + mChildrenCount + ",mFirstTouchTarget = "  

  59.                     + mFirstTouchTarget + ",this = " + this);  

  60.         }  

  61.   

  62.         TouchTarget newTouchTarget = null;  

  63.         boolean alreadyDispatchedToNewTouchTarget = false;  

  64.         if (!canceled && !intercepted) {  

  65.             if (actionMasked == MotionEvent.ACTION_DOWN  

  66.                     || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)  

  67.                     || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {  

  68.                 final int actionIndex = ev.getActionIndex(); // always 0 for down  

  69.                 final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)  

  70.                         : TouchTarget.ALL_POINTER_IDS;  

  71.   

  72.                 // Clean up earlier touch targets for this pointer id in case they  

  73.                 // have become out of sync.  

  74.                 removePointersFromTouchTargets(idBitsToAssign);  

  75.   

  76.                 final int childrenCount = mChildrenCount;  

  77.                 if (newTouchTarget == null && childrenCount != 0) {  

  78.                     final float x = ev.getX(actionIndex);  

  79.                     final float y = ev.getY(actionIndex);  

  80.                     // Find a child that can receive the event.  

  81.                     // Scan children from front to back.  

  82.                     final View[] children = mChildren;  

  83.   

  84.                     final boolean customOrder = isChildrenDrawingOrderEnabled();  

  85.                     for (int i = childrenCount - 1; i >= 0; i--) {  

  86.                         final int childIndex = customOrder ?  

  87.                                 getChildDrawingOrder(childrenCount, i) : i;  

  88.                         final View child = children[childIndex];  

  89.                         if (!canViewReceivePointerEvents(child)  

  90.                                 || !isTransformedTouchPointInView(x, y, child, null)) {  

  91.                             if (DBG_MOTION) {  

  92.                                 Xlog.d(TAG, "(ViewGroup)dispatchTouchEvent continue 6: i = "  

  93.                                         + i + ",count = " + childrenCount + ",child = " + child  

  94.                                         + ",this = " + this);  

  95.                             }  

  96.                             continue;  

  97.                         }  

  98.   

  99.                         newTouchTarget = getTouchTarget(child);  

  100.                         if (DBG_MOTION) {  

  101.                             Xlog.d(TAG, "(ViewGroup)dispatchTouchEvent to child 3: child = "  

  102.                                     + child + ",childrenCount = " + childrenCount + ",i = " + i  

  103.                                     + ",newTouchTarget = " + newTouchTarget + ",idBitsToAssign = "   

  104.                                     + idBitsToAssign + ",mFirstTouchTarget = " + mFirstTouchTarget   

  105.                                     + ",this = " + this);  

  106.                         }  

  107.                         if (newTouchTarget != null) {  

  108.                             // Child is already receiving touch within its bounds.  

  109.                             // Give it the new pointer in addition to the ones it is handling.  

  110.                             newTouchTarget.pointerIdBits |= idBitsToAssign;  

  111.                             break;  

  112.                         }  

  113.   

  114.                         resetCancelNextUpFlag(child);  

  115.                         if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {  

  116.                             // Child wants to receive touch within its bounds.  

  117.                             mLastTouchDownTime = ev.getDownTime();  

  118.                             mLastTouchDownIndex = childIndex;  

  119.                             mLastTouchDownX = ev.getX();  

  120.                             mLastTouchDownY = ev.getY();  

  121.                             newTouchTarget = addTouchTarget(child, idBitsToAssign);  

  122.                             alreadyDispatchedToNewTouchTarget = true;  

  123.                             break;  

  124.                         }  

  125.                     }  

  126.                 }  

  127.   

  128.                 if (newTouchTarget == null && mFirstTouchTarget != null) {  

  129.                     // Did not find a child to receive the event.  

  130.                     // Assign the pointer to the least recently added target.  

  131.                     newTouchTarget = mFirstTouchTarget;  

  132.                     while (newTouchTarget.next != null) {  

  133.                         newTouchTarget = newTouchTarget.next;  

  134.                     }  

  135.                     newTouchTarget.pointerIdBits |= idBitsToAssign;  

  136.                 }  

  137.             }  

  138.         }  

  139.   

  140.         // Dispatch to touch targets.  

  141.         if (mFirstTouchTarget == null) {  

  142.             // No touch targets so treat this as an ordinary view.  

  143.             handled = dispatchTransformedTouchEvent(ev, canceled, null,  

  144.                     TouchTarget.ALL_POINTER_IDS);  

  145.         } else {  

  146.             // Dispatch to touch targets, excluding the new touch target if we already  

  147.             // dispatched to it.  Cancel touch targets if necessary.  

  148.             TouchTarget predecessor = null;  

  149.             TouchTarget target = mFirstTouchTarget;  

  150.             while (target != null) {  

  151.                 final TouchTarget next = target.next;  

  152.                 if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {  

  153.                     handled = true;  

  154.                 } else {  

  155.                     final boolean cancelChild = resetCancelNextUpFlag(target.child)  

  156.                             || intercepted;  

  157.                     if (dispatchTransformedTouchEvent(ev, cancelChild,  

  158.                             target.child, target.pointerIdBits)) {  

  159.                         handled = true;  

  160.                     }  

  161.                     if (DBG_MOTION) {  

  162.                         Xlog.d(TAG, "dispatchTouchEvent middle 5: cancelChild = " + cancelChild  

  163.                                 + ",mFirstTouchTarget = " + mFirstTouchTarget + ",target = "  

  164.                                 + target + ",predecessor = " + predecessor + ",next = " + next  

  165.                                 + ",this = " + this);  

  166.                     }  

  167.                     if (cancelChild) {  

  168.                         if (predecessor == null) {  

  169.                             mFirstTouchTarget = next;  

  170.                         } else {  

  171.                             predecessor.next = next;  

  172.                         }  

  173.                         target.recycle();  

  174.                         target = next;  

  175.                         continue;  

  176.                     }  

  177.                 }  

  178.                 predecessor = target;  

  179.                 target = next;  

  180.             }  

  181.         }  

  182.   

  183.         // Update list of touch targets for pointer up or cancel, if needed.  

  184.         if (canceled  

  185.                 || actionMasked == MotionEvent.ACTION_UP  

  186.                 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {  

  187.             resetTouchState();  

  188.         } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {  

  189.             final int actionIndex = ev.getActionIndex();  

  190.             final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);  

  191.             removePointersFromTouchTargets(idBitsToRemove);  

  192.         }  

  193.     }  

  194.   

  195.     if (DBG_MOTION) {  

  196.         Xlog.d(TAG, "(ViewGroup)dispatchTouchEvent end 4: handled = " + handled + ",mFirstTouchTarget = "  

  197.                 + mFirstTouchTarget + ",this = " + this);  

  198.     }  

  199.   

  200.     if (!handled && mInputEventConsistencyVerifier != null) {  

  201.         mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);  

  202.     }  

  203.     return handled;  



向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI