Android event distribution mechanism

Source: Internet
Author: User

Android event distribution mechanism

 

Many explanations on the Android event distribution mechanism on the Internet are not clear enough, this article will take you from the Touch event generation to the Touch event consumption process for a comprehensive analysis.

Generate Touch events

This part involves hardware and Linux kernel. We will briefly introduce this part. If you are interested, please refer to this article.

Transfer Touch events

A touch event is managed by an Input subsystem of the Linux kernel./dev/input/Create a hardware input device node in this path (the hardware device here is our touch screen ). When the touch screen is triggered by a finger, the hardware reports an event through the device node like the kernel (in fact, managed by InputManager,InputManagerAfter processing, the event is sent to a system Service in the Android system:WindowManagerService.

WindowManagerServiceCall dispatchPointer () to find the WindowState that can receive the current touch event from the z-order sequence list that stores the WindowState, and send the message to the IWindow server (IWindow. stub subclass), this IWindow. stub belongs to ViewRoot (this class inherits Handler and is mainly used to connect PhoneWindow and WindowManagerService), so the event is passed to ViewRoot. dispatchPointer.

Let's take a look at the dispatchPointer method of ViewRoot:

1 public void dispatchPointer(MotionEvent event, long eventTime,2             boolean callWhenDone) {3         Message msg = obtainMessage(DISPATCH_POINTER);4         msg.obj = event;5         msg.arg1 = callWhenDone ? 1 : 0;6         sendMessageAtTime(msg, eventTime);7     }

The dispatchPointer method encapsulates the event as a Message and sends it out. It is processed in the handleMessage of ViewRoot Handler and calls mView. dispatchTouchEvent method (mView is a PhoneWindow. decorView object), PhoneWindow. decorView inherits FrameLayout (FrameLayout inherits ViewGroup and ViewGroup inherits from View). The dispatchTouchEvent method in DecorView is as follows. the cb of Callback is actually the set Callback in the attach () method of the Activity.

1 // in file PhoneWindow. java 2 public boolean dispatchTouchEvent (MotionEvent ev) {3 final Callback cb = getCallback (); 4 if (mEnableFaceDetection) {5 int pointCount = ev. getPointerCount (); 6 7 switch (ev. getAction () & MotionEvent. ACTION_MASK) {8 case MotionEvent. ACTION_POINTER_DOWN: 9 10 ....... 11 12 return cb! = Null &&! IsDestroyed () & mFeatureId <0? Cb. dispatchTouchEvent (ev) 13: super. dispatchTouchEvent (ev); 14} 15 // in file Activity. java-> attach () 16 mFragments. attachActivity (this, mContainer, null); 17 mWindow = PolicyManager. makeNewWindow (this); 18 mWindow. setCallback (this); // sets the callback

In other words, under normal circumstances, the current Activity is the cb, that is, the dispatchTouchEvent method of the Activity is called.

Next we will analyze the event transfer and processing process from Activity to each sub-View.

First, analyze the dispatchTouchEvent method of the Activity.

1 public boolean dispatchTouchEvent(MotionEvent ev) {2         if (ev.getAction() == MotionEvent.ACTION_DOWN) {3             onUserInteraction();4         }5         if (getWindow().superDispatchTouchEvent(ev)) {6             return true;7         }8         return onTouchEvent(ev);9     }

OnUserInteraction () is an empty method. developers can override this method as needed (this method will certainly be called during the cycle of a Touch event ). If True is returned, the current event will not be propagated. What does superDispatchTouchEvent (ev) do? GetWindow (). superDispatchTouchEvent (ev) is called.PhoneWindow.superDispatchTouchEventMethod, and the returned method is mDecor. superDispatchTouchEvent (event), calls super. dispatchTouchEvent (event), and DecorView inherits from ViewGroup (through FrameLayout, FrameLayout does not have dispatchTouchEvent), and finally calls the dispatchTouchEvent method of ViewGroup.

Summary. The Event first arrives at the dispatchTouchEvent method of the DecorView in PhoneWindow. This method calls the dispatchTouchEvent method of the Activity through CallBack. In the Activity, we can override the dispatchTouchEvent method of the Activity to block the propagation of the touch Event. Then, in the dispatchTouchEvent method of the Activity, the event is passed to DecorView again. DecorView sends the event to the parent class for processing by calling the dispatchTouchEvent of the parent class, that is, the method to be analyzed below. This is the touch event transfer process described in most articles on the Internet.

Why do I need to upload the file from PhoneWindow. DecorView to the Activity and then return it to PhoneWindow. DecorView? This mechanism is mainly used to control distribution of current Activity events by controlling dispatchTouchEvent in the Activity. This mechanism is applied in the next article on data tracking.

OK. We need to analyze the dispatchTouchEvent method in ViewGroup.

1 @ Override 2 public boolean dispatchTouchEvent (MotionEvent ev) {3 //...... 4 5 // Check for interception. 6 final boolean intercepted; // whether it is intercepted 7 if (actionMasked = MotionEvent. ACTION_DOWN 8 | mFirstTouchTarget! = Null) {// Touch press event 9 final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT )! = 0; 10 if (! DisallowIntercept) {11 intercepted = onInterceptTouchEvent (ev); // You can override this method to determine whether the message needs to be intercepted by viewGroup, 12 // the premise for overwriting to take effect is that disallowIntercept is FALSE, otherwise 13 ev is useless if it is written. setAction (action); // restore action in case it was changed 14} else {// intercepted 15 = false is not allowed; 16} 17} else {18 // There are no touch targets and this action is not an initial down 19 // so this view group continues to intercept touches. 20 // this operation is not the first down event. We set it to TRUE and intercepted 21 = true; 22} 23 24 // Check for cancelation. 25 final boolean canceled = resetCancelNextUpFlag (this) 26 | actionMasked = MotionEvent. ACTION_CANCEL; 27 28 //......... 29 30 final int childrenCount = mChildrenCount; // ViewGroup neutron View count 31 if (newTouchTarget = null & childrenCount! = 0) {32 final float x = ev. getX (actionIndex); // obtains coordinates for comparing 33 final float y = ev. getY (actionIndex); 34 // Find a child that can receive the event. 35 // Scan children from front to back. 36 final View [] children = mChildren; // obtain all the sub-views of the viewgroup 37 38 final boolean customOrder = isChildrenDrawingOrderEnabled (); // The draw sequence of the subview is 39 // traverse all the subviews from high to low and find the child View 40 for (int I = childrenCount- 1; I> = 0; I --) {41 final int childIndex = customOrder? 42 getChildDrawingOrder (childrenCount, I): I; // obtain the subview 43 final view child = children [childIndex] According to the Order; 44 // determine whether the View 45 if (! CanViewReceivePointerEvents (child) 46 |! IsTransformedTouchPointInView (x, y, child, null) {47 continue; 48} 49 50 newTouchTarget = getTouchTarget (child); // view the child 51 if (newTouchTarget! = Null) {// locate the Child view 52 // Child is already refreshing touch within its bounds. 53 // Give it the new pointer in addition to the ones it is handling. 54 // found. The loop ends. The target is newTouchTarget 55 newTouchTarget. pointerIdBits | = idBitsToAssign; 56 break; 57} 58 59 //....... 60} 61} 62} 63} 64 65 // Dispatch to touch targets. 66 if (mFirstTouchTarget = null) {67 // No touch targets so treat this as an ord Inary view. 68/* in the dispatchTransformedTouchEvent method, if child is null, super is called. dispatchTouchEvent, 69 *, that is, the dispatchTouchEvent of the parent Class View of the ViewGroup (if we have intercepted the touch event before, it will be handled like this). 70 * if it is not null, the child is called. dispatchTouchEvent. 71 **/72 handled = dispatchTransformedTouchEvent (ev, canceled, null, 73 TouchTarget. ALL_POINTER_IDS); 74} else {75 //.... 76} 77 //........ 78 return handled; 79} 80/** 81 * Transforms a motion event into the coordinate space of a participant child view, 82 * filters out irrelevant pointer ids, and overrides its action if necessary. 83 * If child is null, assumes the MotionEvent will be sent To this ViewGroup instead. 84 */85 private boolean dispatchTransformedTouchEvent (MotionEvent event, boolean cancel, 86 View child, int desiredPointerIdBits) {87 final boolean handled; 88 89 //...... 90 91 // Perform any necessary transformations and dispatch. 92 if (child = null) {93 handled = super. dispatchTouchEvent (transformedEvent); 94} else {95 //...... 96 handled = child. dispatchTouchEvent (transformedEvent); 97} 98 99 // Done.100 //...... 101 return handled; 102}

Let's summarize the call process of the dispatchTouchEvent of ViewGroup.

  1. First, determine whether the MotionEvent can be intercepted. If yes, we can call onInterceptTouchEvent to handle the intercepted event. If this method returns TRUE, it indicates that the interception is required, so far, the event will not be passed to the subview. Note that the onInterceptTouchEvent method returns FALSE by default.
  2. If this Event is not intercepted, find all the sub-views in this ViewGroup, and calculate the coordinates of each sub-View through canViewReceivePointerEvents and isTransformedTouchPointInView, locate the View that matches the coordinates.
  3. Call the dispatchTransformedTouchEvent method to process Event Events.
    1 // ViewGroup. java dispatchTransformedTouchEvent method intercepts 2 if (cancel | oldAction = MotionEvent. ACTION_CANCEL) {3 event. setAction (MotionEvent. ACTION_CANCEL); 4 if (child = null) {// Event intercepted, call the dispatchTouchEvent method of the parent Class View 5 handled = super. dispatchTouchEvent (event); 6} else {7 handled = child. dispatchTouchEvent (event); // call the dispatchTouchEvent method of the sub-View 8} 9 event. setAction (oldAction); 10 return handled; 11}
    1. If this sub-View is a Button, a Button is called. the dispatchTouchEvent method, the Button and its parent class TextView do not have the dispatchTouchEvent method. You can only continue to View the parent class View. In fact, the final call is still View. dispatchTouchEvent method.
    2. We will continue to analyze the View. dispatchTouchEvent method. MOnTouchListener is an OnTouchListener object, which is set by the setOnTouchListener method;
      1 public boolean dispatchTouchEvent (MotionEvent event) {2 if (mInputEventConsistencyVerifier! = Null) {3 mInputEventConsistencyVerifier. onTouchEvent (event, 0); 4} 5 6 if (onFilterTouchEventForSecurity (event) {7 // noinspection SimplifiableIfStatement 8 ListenerInfo li = mListenerInfo; // View internal class, manage some listener 9 if (li! = Null & li. mOnTouchListener! = Null & (mViewFlags & ENABLED_MASK) = ENABLED10 & li. mOnTouchListener. onTouch (this, event) {11 return true; 12} 13 14 if (onTouchEvent (event) {15 return true; 16} 17} 18 19 if (mInputEventConsistencyVerifier! = Null) {20 mInputEventConsistencyVerifier. onUnhandledEvent (event, 0); 21} 22 return false; // if no consumption is lost, only false is returned, which is processed by the caller. 23} 24/** 25 * Register a callback to be invoked when a touch event is sent to this view.26 * @ param l the touch listener to attach to this view27 */28 public void setOnTouchListener (OnTouchListener l) {29 getListenerInfo (). mOnTouchListener = l; 30}

      If the current ListenerInfo method is initialized and the value of li. mOnTouchListener is not empty and the ENABLE mask is Enable, The mOnTouchListener (this, event) method is called.boolean onTouch(View v, MotionEvent event)This method is in the OnTouchListener interface of the View. It is an empty method and needs to be implemented by the user. Take a Button as an example. The onTouch () method we overwrite is called here.

      1 button. setOnTouchListener (new OnTouchListener () {2 @ Override3 public boolean onTouch (View v, MotionEvent event) {4 // implement your own function 5 return true; 6} 7 });
      1. If the onTouch method returns true, it indicates that it is consumed and will not be passed on. If the return value is false, it indicates that the time has not been consumed and will continue to be passed to the onTouchEvent method.
        1 public boolean onTouchEvent (MotionEvent event) {2 //...... 3 if (viewFlags & CLICKABLE) = CLICKABLE | 4 (viewFlags & LONG_CLICKABLE) = LONG_CLICKABLE) {5 switch (event. getAction () {6 case MotionEvent. ACTION_UP: 7 //...... 8 // if the long press event is not triggered and the finger action is up, execute the restore mclick () method 9 if (! MHasPerformedLongPress) {10 // This is a tap, so remove the longpress check11 removeLongPressCallback (); 12 13 // Only perform take click actions if we were in the pressed state14 if (! FocusTaken) {15 // Use a Runnable and post this rather than calling16 // specify mclick directly. this lets other visual state17 // of the view update before click actions start.18 // click Event 19 if (mPerformClick = null) {20 mPerformClick = new custom mclick (); 21} 22 if (! Post (mPerformClick) {23 hour mclick (); 24} 25} 26} 27 28 break; 29 case MotionEvent. ACTION_DOWN: 30 //...... 31 // whether or not to trigger the long press event is determined here. I will not post the details 32 checkForLongClick (0); 33 //...... 34 break; 35 //...... 36} 37 return true; 38} 39 40 return false; 41}

        If the status is not CLICKABLE, return false will be skipped and executed. This means that subsequent touch events will not be handed over. However, as long as it is CLICKABLE, no matter which node of the case is returned to true, it ensures that subsequent events can be transmitted. Obviously, in the onTouchEvent method, it mainly determines which operation should be performed, whether it is long-pressed or clicked, and then executes the corresponding method. Let's take a look at how to execute a click:

        1 public boolean initialize mclick () {2 //...... 3 4 ListenerInfo li = mListenerInfo; 5 if (li! = Null & li. mOnClickListener! = Null) {6 // playback click sound 7 playSoundEffect (SoundEffectConstants. CLICK); 8 // execute The onClick Method 9 li. mOnClickListener. onClick (this); 10 return true; 11} 12 13 return false; 14}

        The onClick method in OnClickListener is called. Therefore, when both onTouch () and onClick () exist, onTouch must be executed first and then onClick; If onTouch intercepts the event, return true directly, the onClick method will not be executed. Here, we have analyzed the entire touch event transfer process.

        Summary of the general call process of Touch events

        The user clicks on the screen to generate a Touch (including DOWN, UP, and MOVE. This article analyzes the DOWN event-> InputManager-> WindowManagerService. dispatchPointer ()-> IWindow. stub-> ViewRoot. dispatchPointer ()-> PhoneWindow. decorView. dispatchTouchEvent ()-> Activity. dispatchTouchEvent ()-> PhoneWindow. superDispatchTouchEvent-> PhoneWindow. decorView. superDispatchTouchEvent-> ViewGroup. dispatchTouchEvent ()-> ViewGroup. dispatchTransformedTouchEvent ()-> sub View. dispatchTouchEvent ()-> sub View. onTouch ()-> sub View. onTouchEvent ()-> event consumption ends

        Useful References
        1. Android FrameWork -- Touch event dispatching process
        2. Android window mechanism analysis ------ Event Processing
        3. The Android event distribution mechanism is completely parsed to give you a thorough understanding of the source code (below)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.