android 判断按钮是否已经有onclicklinstener,通过点击事件监听setOnClickListener彻底理解回调...
前言
老司機們對于回調肯定熟悉得不能再熟悉了,但是新司機可能還是一臉懵逼的,我比較笨,當年懵逼了好久,看夏安明的這一篇博客地址,雖然下邊的留言都是,寫得好!懂了懂了!但是我當時看了三遍還是不懂好嗎 - -,現在我站在我的角度,用我理解的方式給大家講解回調,我這么笨都理解了,聰明的新司機們肯定也是可以的
setOnClickListener分析
setOnCLickLinstener,只要寫過Android的同學應該都見過,大家都知道是點擊事件監聽,但是是怎么實現的呢?對,你沒有猜錯,就是回調
你在onClick(View view)中寫的方法,就是一個回調方法,你仔細想一想,這個方法是在你傳的參數new View.OnClickListener()中的方法,你再仔細的想一想,為什么你傳入了new View.OnClickListener()這個參數,Android Studio就會自動補全,讓你去實現onClick(View
view)這個方法呢?
一切都在你想象之中,OnClickListener就是一個接口,new出一個接口,你就得實現他里邊的抽象方法,在Android中,大多數回調都是靠接口來進行的
并且,你實現了onClick(View view)方法后,這個方法并沒有在我們的Activity或者Fragment中調用,那為什么他生效了呢?這就是回調,你實現了他,而他卻是在另一個地方調用的
那是在什么地方調用的呢?
我們點進setOnClickListener方法中一探虛實
于是我們跳到了View.java,原來這個方法是寫在View中的,這時你想到,第一行代碼中說了,我們的控件都繼承于View,原來如此 public void setOnClickListener(@Nullable OnClickListener l){
if (!isClickable()) {
setClickable(true);
}
getListenerInfo().mOnClickListener = l;
}
復制代碼
setOnClickListener方法就如同我們調用時的那樣,傳入一個OnClickListener對象作為參數,那我們來看一看OnClickListener是個啥子 public interface OnClickListener {
/**
* Called when a view has been clicked.
*
* @param v The view that was clicked.
*/
void onClick(View v);
}
復制代碼
果然不出你所料,就是個interface
然后注意這一行 getListenerInfo().mOnClickListener = l;
復制代碼
把我們傳入的OnClickListener對象賦值給了getListenerInfo().mOnClickListener,記住我們傳入的OnClickListener對象就相當于攜帶了我們實現的onClick(View view)方法,進到View里邊來了
記好了哦!
我們來看看getListenerInfo()方法 ListenerInfo getListenerInfo(){
if (mListenerInfo != null) {
return mListenerInfo;
}
mListenerInfo = new ListenerInfo();
return mListenerInfo;
}
復制代碼
getListenerInfo()返回一個ListenerInfo,如果mListenerInfo已經存在,就返回,如果不存在,就new一個返回,也許你已經知道,或許不久后你就知道,這叫單例模式,保證只有一個ListenerInfo對象
然后我們來看看ListenerInfo又是個啥子 static class ListenerInfo{
protected OnFocusChangeListener mOnFocusChangeListener;
private ArrayList mOnLayoutChangeListeners;
protected OnScrollChangeListener mOnScrollChangeListener;
private CopyOnWriteArrayList mOnAttachStateChangeListeners;
public OnClickListener mOnClickListener;
protected OnLongClickListener mOnLongClickListener;
protected OnContextClickListener mOnContextClickListener;
protected OnCreateContextMenuListener mOnCreateContextMenuListener;
private OnKeyListener mOnKeyListener;
private OnTouchListener mOnTouchListener;
private OnHoverListener mOnHoverListener;
private OnGenericMotionListener mOnGenericMotionListener;
private OnDragListener mOnDragListener;
private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;
OnApplyWindowInsetsListener mOnApplyWindowInsetsListener;
}
復制代碼
原來是一個內部靜態類,成員包括各種事件的監聽接口,其中包括 public OnClickListener mOnClickListener;
復制代碼
誒喲,和我們傳入的一樣的一個OnClickListener接口引用,于是繞了這么一大圈(我們先不管為啥繞),我們傳入的持有我們實現的onClick(View view)方法的OnClickListener接口對象(還記得嗎?),被賦值到了View中的mListenerInfo中的mOnClickListener對象,也就是,我們實現的onCLick(View view) 方法,被mListenerInfo.mOnClickListener持有了
這時,你應該想到了,我們實現的onClick(View view)應該就是在 View中被調用了,bingo! public boolean performClick(){
final boolean result;
final ListenerInfo li = mListenerInfo;
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
li.mOnClickListener.onClick(this);
result = true;
} else {
result = false;
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
return result;
}
復制代碼
從字面意思理解,這個方法就是執行Click的方法,
他將mListenerInfo對象傳給了一個靜態的ListenerInfo對象,
li,后邊的故事大家都知道了 li.mOnClickListener.onClick(this);
復制代碼
這個方法執行了點擊事件,并調用了我們實現的onClick(View view) 方法
讓我們來梳理一遍流程,我們在Activity或者Fragment中調用
View.setOnClickListener方法,傳入一個OnCLickListener對象,實現了onCLick(View view)方法,然后在View中的某個地方,我們實現的onCLick(View view)被調用,實現了回調,這就是回調的流程
異步
回調有什么用呢,就是異步,想象一下,系統一直在監聽著屏幕的點擊事件,在我們觸摸到屏幕的時候進行響應,這是一個線程操作,因為如果這個放在主線程,那在事件被響應之前,我們的線程都是阻塞的,因為屏幕的資源被占用了,無法進行其他操作,而在子線程中,系統監聽著屏幕的活動,然后在我們觸摸時,調用performClick()方法實現了點擊,并且調用了onClick(View view)方法實現了點擊事件的回調,我們就可以恰恰剛好在點擊時間觸發的時候,進行我們想要的操作,也就是我們實現的on
CLick(View view)方法
半偽代碼實現一個回調給你看
A.class //先定義一個接口
public interface Listener {
//回調方法
void 回調方法();
}
//申明一個接口
private Listener mLinstener;
//一個set接口的方法
public void setListener(Listener listener){
//把傳入的listener賦值給mLinstener
mLinstener = listener
}
...
//在某個地方,進行某個操作的時候
private void 某個操作() {
//回調方法執行
mLinstener.回調方法();
}
復制代碼
另一個類 B.class private A a = new A();
a.setListener(new Linstener() {
public void 回調方法() {
//我要在A中某個操作()執行的時候要搞的事情
搞事情阿搞事情();
}
});
復制代碼
然后在某個操作()調用的時候,我們的回調方法()也就被調用開始搞事情了
你如果看不懂的話,自己寫一遍,這就是Android中回調的一般寫法,你可以在各種自定義View中用來了,用著用著就理解了
為啥要繞那一圈
那一圈保證了View中只有一個mOnClickListener對象,保證了我們一次只執行一次onClick() 方法
最后
新司機們如果覺得有幫助,麻煩請給我的github項目點一個star
地址點這里
總結
以上是生活随笔為你收集整理的android 判断按钮是否已经有onclicklinstener,通过点击事件监听setOnClickListener彻底理解回调...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C语言整数加法器,【菜鸟解析】C++大数
- 下一篇: android:shareduserid