Android View 觸摸屏事件派發機制和源碼分析

分類:編程 時間:2017-02-15

android View 觸摸屏事件派發機制和源碼分析

最近參考Android systemUI 的源碼其中涉及到很多事件派發和處理相關的問題.早期感覺很復雜,後面有時間了通過結合log來分析漸漸有一定的理解.現在參考網絡上面的文章自己也將這一方面的源碼分析一下,同時寫下來,以便然後回憶和加深理解.(基於mtk 的Android 5.1 系統)


Android 的觸摸事件都是從dispatchTouchEvent()開始的,View 和ViewGroup 都是一樣的.暫時只分析View,不分析ViewGroup.

1.View 的dispatchTouchEvent()開始

其實View的dispatchTouchEvent也是有父布局(某個ViewGroup,可以理解為LinerLayout)調用的.直接上源碼.
在判斷是ACTION_DOWN之前dispatchTouchEvent 做了處理手勢相關的工作(mInputEventConsistencyVerifier),這個具體還沒有研究,以後再研究,在筆記的後面有一個"Android的用戶輸入處理"可以參考.目前只是分析我們需要關註的重點.
  1. public boolean dispatchTouchEvent(MotionEvent event) {
  2. // If the event should be handled by accessibility focus first.
  3. if (event.isTargetAccessibilityFocus()) {
  4. // We don't have focus or no virtual descendant has it, do not handle the event.
  5. if (!isAccessibilityFocusedViewOrHost()) {
  6. return false;
  7. }
  8. // We have focus and got the event, then use normal event dispatch.
  9. event.setTargetAccessibilityFocus(false);
  10. }
  11. boolean result = false;
  12. if (mInputEventConsistencyVerifier != null) {
  13. mInputEventConsistencyVerifier.onTouchEvent(event, 0);
  14. }
  15. if (DBG_MOTION || DEBUG_DEFAULT) {
  16. if (event.getAction() == MotionEvent.ACTION_DOWN) {
  17. Xlog.i(VIEW_LOG_TAG, "Touch down dispatch to " + this + ", event = " + event);
  18. } else if (event.getAction() == MotionEvent.ACTION_UP) {
  19. Xlog.i(VIEW_LOG_TAG, "Touch up dispatch to " + this + ", event = " + event);
  20. }
  21. }
  22. if (DBG_MOTION) {
  23. Xlog.d(VIEW_LOG_TAG, "(View)dispatchTouchEvent: event = " + event + ",this = " + this);
  24. }
  25. final int actionMasked = event.getActionMasked();
  26. if (actionMasked == MotionEvent.ACTION_DOWN) {
  27. // Defensive cleanup for new gesture
  28. stopNestedScroll();
  29. }
  30. if (onFilterTouchEventForSecurity(event)) {//判斷當前View 沒有被遮蔽
  31. //noinspection SimplifiableIfStatement
  32. ListenerInfo li = mListenerInfo;
  33. if (li != null && li.mOnTouchListener != null
  34. && (mViewFlags & ENABLED_MASK) == ENABLED
  35. && li.mOnTouchListener.onTouch(this, event)) {//1.設置touchListener,2.是enable狀態,3.touchListener的onTouch返回true
  36. /// M : add log to help debugging
  37. if (DBG_TOUCH) {
  38. Xlog.d(VIEW_LOG_TAG, "handle Touch event by listerner, listener = " + li
  39. + ", event = " + event + ", this = " + this);
  40. }
  41. result = true;
  42. }
  43. if (!result && onTouchEvent(event)) {//touchListener的onTouch沒有返回false,或者沒有設置clickListener/longClickListener,而且onTouchEvent返回true.而且onTouchEvent返回什麽dispatchTouchEvent也會返回什麽
  44. /// M : add log to help debugging
  45. if (DBG_TOUCH) {
  46. Xlog.d(VIEW_LOG_TAG, "handle Touch event by onTouchEvent, event = "
  47. + event + ", this = " + this);
  48. }
  49. result = true;
  50. }
  51. }
  52. /// M : add log to help debugging
  53. if (!result && DBG_TOUCH) {
  54. Xlog.d(VIEW_LOG_TAG, "Do not handle Touch event, event = "
  55. + event + ", this = " + this);
  56. }
  57. if (!result && mInputEventConsistencyVerifier != null) {
  58. mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
  59. }
  60. // Clean up after nested scrolls if this is the end of a gesture;
  61. // also cancel it if we tried an ACTION_DOWN but we didn't want the rest
  62. // of the gesture.
  63. if (actionMasked == MotionEvent.ACTION_UP ||
  64. actionMasked == MotionEvent.ACTION_CANCEL ||
  65. (actionMasked == MotionEvent.ACTION_DOWN && !result)) {
  66. stopNestedScroll();
  67. }
  68. return result;
  69. }
onFilterTouchEventForSecurity裏面看註釋就知道是判斷當前的View 有沒有被遮蔽.我們考慮的是沒有被遮蔽的情況,了就是onFilterTouchEventForSecurity返回true. dispatchTouchEvent 在39行有一個if判斷,這個判斷依次做了3個小判斷. if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) 第一步:li != null && li.mOnTouchListener != null,這個ListenerInfo 是不是為null並且mListenerInfo的mOnTouchListener  是不是為null.在View 的源碼裏面查找mListenerInfo就會找到是在getListenerInfo裏面調用的,接著會發現是在setOnClickListener裏面調用的.顯然也就是我們判斷我們也沒有給這個View 控件設置View.OnClickListener事件.如果有就已經第2部分的判斷
  1. ListenerInfo getListenerInfo() {
  2. if (mListenerInfo != null) {
  3. return mListenerInfo;
  4. }
  5. mListenerInfo = new ListenerInfo();
  6. return mListenerInfo;
  7. }
  8. public void setOnClickListener(OnClickListener l) {
  9. if (!isClickable()) {
  10. setClickable(true);
  11. }

  12. Tags:

    文章來源:


ads
ads

相關文章
ads

相關文章

ad