標籤:
今天的CSDN公開課Android事件處理重痛點快速掌握中老師講到一個概念我覺得不正確。
原話是這樣的:點擊事件可以通過事件監聽和回調兩種方法實現。
我一聽到之後我的表情是這樣的:
這跟我學的看的都不一樣啊,這還分監聽和回調。這個時候我立馬提出問題,嗯,講課老師看到了。
老師就說了:是不一樣的,我們第四點(最後一點)會講。
好,我立馬坐好準備受教聽了大半小時。聽到最後我的表情是這樣的:
廢話說夠了,開個小玩笑,不要見怪。
我們都知道,監聽事件其實只有一種,就是回調。如果有人不明白什麼是回調?可以看看我的一篇文章中的開頭那個例子:回調學習筆記
我們以Button為例,Button是View的子類這個毋庸置疑,所以我們直接看View中的源碼:
public void setOnClickListener(@Nullable OnClickListener l) { if (!isClickable()) { setClickable(true); } getListenerInfo().mOnClickListener = l; }
這裡很簡單,只是把一個OnClickListener的具體子類儲存起來而已。當我們點擊按鈕的時候,系統必然會回調onTouchEvent這個方法,而在View中這個方法是這樣的:
1 public boolean onTouchEvent(MotionEvent event) { 2 final float x = event.getX(); 3 final float y = event.getY(); 4 final int viewFlags = mViewFlags; 5 final int action = event.getAction(); 6 7 // 代碼省略 8 9 if (((viewFlags & CLICKABLE) == CLICKABLE ||10 (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||11 (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {12 switch (action) {13 case MotionEvent.ACTION_UP:14 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;15 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {16 boolean focusTaken = false;17 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {18 focusTaken = requestFocus();19 }20 21 if (prepressed) {22 setPressed(true, x, y);23 }24 25 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {26 if (!focusTaken) {27 28 if (mPerformClick == null) {29 mPerformClick = new PerformClick();30 }31 if (!post(mPerformClick)) {32 performClick();33 }34 }35 }36 37 if (mUnsetPressedState == null) {38 mUnsetPressedState = new UnsetPressedState();39 }40 41 if (prepressed) {42 postDelayed(mUnsetPressedState,43 ViewConfiguration.getPressedStateDuration());44 } else if (!post(mUnsetPressedState)) {45 mUnsetPressedState.run();46 }47 48 removeTapCallback();49 }50 mIgnoreNextUpEvent = false;51 break;52 53 case MotionEvent.ACTION_DOWN:54 // 代碼省略55 break;56 57 case MotionEvent.ACTION_CANCEL:58 // 代碼省略59 break;60 61 case MotionEvent.ACTION_MOVE:62 // 代碼省略63 break;64 }65 66 return true;67 }68 69 return false;70 }
這裡我刪除了很多代碼,我們知道一個點擊是由一個ACTION_DOWN、若干個ACTION_MOVE和一個ACTION_UP組成的,也就是說,當點擊完成,會執行ACTION_UP中的代碼。在第32行中,調用了一個方法叫做performClick,這個方法就是直接執行點擊事件的,我們看到這個方法的內部:
1 public boolean performClick() { 2 final boolean result; 3 final ListenerInfo li = mListenerInfo; 4 if (li != null && li.mOnClickListener != null) { 5 playSoundEffect(SoundEffectConstants.CLICK); 6 li.mOnClickListener.onClick(this); 7 result = true; 8 } else { 9 result = false;10 }11 12 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);13 return result;14 }
第6行中,調用了我們傳進來的那個介面的實作類別中的onClick方法,這就是回調,因為這不是真正的調用。
總結:無論是什麼監聽事件,都是通過回調來實現的。我們點擊之後,事件由系統捕獲,有底層控制項逐步上傳到控制項,然後回調給View的onTouchEvent方法,這個方法回調給我們設定的介面中onClick方法。我固然知道回調和監聽不同,但是它們絕對不會是兩種方法。
Android開發學習之路-記一次CSDN公開課