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數了。