1. 程式人生 > >Android事件分發機制一 系統預設機制

Android事件分發機制一 系統預設機制

1.為什麼要了解Android事件機制?

背景:我在做Android專案的時候遇到一個Activity->Fragment->ScrollView->Button這樣的巢狀關係,當一切都準備就緒,程式啟動後點擊Button的時候系統異常崩潰了,騰訊Bugly抓到後報以下錯誤。

java.lang.IllegalArgumentException

Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter e1

 不用看了就是傳遞的引數有問題,要解決這個問題就必須要了解Android的事件分發機制。

2.如何解決。

先讓我來看一Android事件分發機制的張圖

從上圖中可以看出當點選Activity上的某一個View的時候,Android展示了它完整的系統預設事件分發機制Activity->viewGroup->view。

Activity(DispatchTouchEvent)->(VIewGroup)DispatchTouchEvents->(VIewGroup)onInterceptTouchEvent->(view)dispatchTouchEvent->(View)OnTouchEvent

案例1:

新建一個DispatchEvent專案;

新建一個MyLinearLayout

class MyLinearLayout(context:Context): LinearLayout(context)
{
    override  fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
        when(ev?.action)
        {
            MotionEvent.ACTION_DOWN->{
                Log.d("GroupView_dispatchEvent","ACTION_DOWN")}
            MotionEvent.ACTION_MOVE->{Log.d("GroupView_dispatchEvent","ACTION_MOVE")}
            MotionEvent.ACTION_UP->{Log.d("GroupView_dispatchEvent","ACTION_UP")}
            MotionEvent.ACTION_CANCEL->{
                (Log.d("GroupView_dispatchEvent","ACTION_CANCEL"))
            }
        }

        return super.dispatchTouchEvent(ev)
    }

    override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
        when(ev?.action)
        {
            MotionEvent.ACTION_DOWN->{Log.d("GroupView_onIntercept","ACTION_DOWN")}
            MotionEvent.ACTION_MOVE->{Log.d("GroupView_onIntercept","ACTION_MOVE")}
            MotionEvent.ACTION_UP->{Log.d("GroupView_onIntercept","ACTION_UP")}
            MotionEvent.ACTION_CANCEL->{Log.d("GroupView_onIntercept","ACTION_CANCEL")}
        }
        return super.onInterceptTouchEvent(ev)
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        when(event?.action)
        {
            MotionEvent.ACTION_DOWN->{Log.d("GroupView_onTouchEvent","ACTION_DOWN")}
            MotionEvent.ACTION_MOVE->{Log.d("GroupView_onTouchEvent","ACTION_MOVE")}
            MotionEvent.ACTION_UP->{Log.d("GroupView_onTouchEvent","ACTION_UP")}
            MotionEvent.ACTION_CANCEL->{Log.d("GroupView_onTouchEvent","ACTION_CANCEL")}
        }
        return super.onTouchEvent(event)
    }
}

2.新建一個MyButton

class MyButton(context:Context): Button(context)
{
    override  fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
        when(ev?.action)
        {
            MotionEvent.ACTION_DOWN->{    Log.d("View_dispatchEvent","ACTION_DOWN")}
            MotionEvent.ACTION_MOVE->{    Log.d("View_dispatchEvent","ACTION_MOVE")}
            MotionEvent.ACTION_UP->{    Log.d("View_dispatchEvent","ACTION_UP")}
            MotionEvent.ACTION_CANCEL->{
                Log.d("View_dispatchEvent","ACTION_CANCEL")
            }
        }
        return super.dispatchTouchEvent(ev)
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        when(event?.action)
        {
            MotionEvent.ACTION_DOWN->{Log.d("View_onTouchEvent","ACTION_DOWN")}
            MotionEvent.ACTION_MOVE->{Log.d("View_onTouchEvent","ACTION_MOVE")}
            MotionEvent.ACTION_UP->{Log.d("View_onTouchEvent","ACTION_UP")}
            MotionEvent.ACTION_CANCEL->{Log.d("View_onTouchEvent","ACTION_CANCEL")}
        }
        Log.d("View_onTouchEvent","我是最後的消費者${super.onTouchEvent(event)}")
        return super.onTouchEvent(event)
    }
}

3.在MainActivity寫上如下程式碼

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        var myLinearLayout = MyLinearLayout(this);
        var myButton = MyButton(this);
        myButton.setText("MyButton")

        var viewGroups:ViewGroup.LayoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);

        var viewPar:ViewGroup.LayoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);
        myLinearLayout.orientation = LinearLayout.VERTICAL;
        myLinearLayout.addView(myButton,viewPar);

        setContentView(myLinearLayout,viewGroups);
    }

    override  fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
        when(ev?.action)
        {
            MotionEvent.ACTION_DOWN->{  Log.d("Activity_dispatchEvent","ACTION_DOWN")}
            MotionEvent.ACTION_MOVE->{  Log.d("Activity_dispatchEvent","ACTION_MOVE")}
            MotionEvent.ACTION_UP->{  Log.d("Activity_dispatchEvent","ACTION_UP")}
            MotionEvent.ACTION_CANCEL->{
                Log.d("Activity_dispatchEvent","ACTION_CANCEL")
            }
        }

        return super.dispatchTouchEvent(ev)
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        when(event?.action)
        {
            MotionEvent.ACTION_DOWN->{Log.d("Activity_onTouchEvent","ACTION_DOWN")}
            MotionEvent.ACTION_MOVE->{Log.d("Activity_onTouchEvent","ACTION_MOVE")}
            MotionEvent.ACTION_UP->{Log.d("Activity_onTouchEvent","ACTION_UP")}
            MotionEvent.ACTION_CANCEL->{Log.d("Activity_onTouchEvent","ACTION_CANCEL")}
        }
        return super.onTouchEvent(event)
    }

}

點選Butuon觀察列印資訊

09-29 00:20:11.109 8276-8276/com.example.krcm110.myapplication D/Activity_dispatchEvent: ACTION_DOWN 09-29 00:20:11.116 8276-8276/com.example.krcm110.myapplication D/GroupView_dispatchEvent: ACTION_DOWN 09-29 00:20:11.117 8276-8276/com.example.krcm110.myapplication D/GroupView_onIntercept: ACTION_DOWN 09-29 00:20:11.118 8276-8276/com.example.krcm110.myapplication D/View_dispatchEvent: ACTION_DOWN 09-29 00:20:11.118 8276-8276/com.example.krcm110.myapplication D/View_onTouchEvent: ACTION_DOWN 09-29 00:20:11.151 8276-8276/com.example.krcm110.myapplication D/View_onTouchEvent: 我是最後的消費者true 09-29 00:20:11.154 8276-8276/com.example.krcm110.myapplication D/Activity_dispatchEvent: ACTION_UP 09-29 00:20:11.154 8276-8276/com.example.krcm110.myapplication D/GroupView_dispatchEvent: ACTION_UP 09-29 00:20:11.155 8276-8276/com.example.krcm110.myapplication D/GroupView_onIntercept: ACTION_UP 09-29 00:20:11.155 8276-8276/com.example.krcm110.myapplication D/View_dispatchEvent: ACTION_UP 09-29 00:20:11.155 8276-8276/com.example.krcm110.myapplication D/View_onTouchEvent: ACTION_UP 09-29 00:20:11.156 8276-8276/com.example.krcm110.myapplication D/View_onTouchEvent: 我是最後的消費者true

以上就是一個完整的事件派發如圖1.

4.如果我們點選後不立馬鬆開並且滑鼠移動後再鬆開

09-29 00:30:45.177 8276-8276/com.example.krcm110.myapplication D/Activity_dispatchEvent: ACTION_DOWN 09-29 00:30:45.177 8276-8276/com.example.krcm110.myapplication D/GroupView_dispatchEvent: ACTION_DOWN 09-29 00:30:45.177 8276-8276/com.example.krcm110.myapplication D/GroupView_onIntercept: ACTION_DOWN 09-29 00:30:45.177 8276-8276/com.example.krcm110.myapplication D/View_dispatchEvent: ACTION_DOWN 09-29 00:30:45.177 8276-8276/com.example.krcm110.myapplication D/View_onTouchEvent: ACTION_DOWN 09-29 00:30:45.193 8276-8276/com.example.krcm110.myapplication D/View_onTouchEvent: 我是最後的消費者true09-29 00:30:45.328 8276-8276/com.example.krcm110.myapplication D/Activity_dispatchEvent: ACTION_MOVE 09-29 00:30:45.328 8276-8276/com.example.krcm110.myapplication D/GroupView_dispatchEvent: ACTION_MOVE 09-29 00:30:45.329 8276-8276/com.example.krcm110.myapplication D/GroupView_onIntercept: ACTION_MOVE 09-29 00:30:45.329 8276-8276/com.example.krcm110.myapplication D/View_dispatchEvent: ACTION_MOVE 09-29 00:30:45.329 8276-8276/com.example.krcm110.myapplication D/View_onTouchEvent: ACTION_MOVE     我是最後的消費者true09-29 00:30:45.572 8276-8276/com.example.krcm110.myapplication D/Activity_dispatchEvent: ACTION_UP 09-29 00:30:45.572 8276-8276/com.example.krcm110.myapplication D/GroupView_dispatchEvent: ACTION_UP 09-29 00:30:45.572 8276-8276/com.example.krcm110.myapplication D/GroupView_onIntercept: ACTION_UP 09-29 00:30:45.572 8276-8276/com.example.krcm110.myapplication D/View_dispatchEvent: ACTION_UP 09-29 00:30:45.572 8276-8276/com.example.krcm110.myapplication D/View_onTouchEvent: ACTION_UP 09-29 00:30:45.573 8276-8276/com.example.krcm110.myapplication D/View_onTouchEvent: 我是最後的消費者true

總結:以上就是一個系統預設的Android事件機制。相信你心裡面已經有些B數了。