1. 程式人生 > >Android開發,addlistener和setlistener的區別

Android開發,addlistener和setlistener的區別

做Android開發稍微久一點的都知道,android之前的監聽器基本都是setlistener,比如setOnClickListener,setTextChangeListener。

但是後來,android中很多的setlistener都被廢棄了,用addlistener來替代,比如上面的setTextChangeListener。

本文主要就是用於探討setlistener和addlistener的區別。

我們就以setOnClickListener和addTextChangedListener舉例

1、檢視原始碼

/**
     * Register a callback to be invoked when this view is clicked. If this view is not
     * clickable, it becomes clickable.
     *
     * @param l The callback that will run
     *
     * @see #setClickable(boolean)
     */
    public void setOnClickListener(@Nullable OnClickListener l) {
        if (!isClickable()) {
            setClickable(true);
        }
        getListenerInfo().mOnClickListener = l;
    }
/**
     * Adds a TextWatcher to the list of those whose methods are called
     * whenever this TextView's text changes.
     * <p>
     * In 1.0, the {@link TextWatcher#afterTextChanged} method was erroneously
     * not called after {@link #setText} calls.  Now, doing {@link #setText}
     * if there are any text changed listeners forces the buffer type to
     * Editable if it would not otherwise be and does call this method.
     */
    public void addTextChangedListener(TextWatcher watcher) {
        if (mListeners == null) {
            mListeners = new ArrayList<TextWatcher>();
        }

        mListeners.add(watcher);
    }
可以看到,setListener直接是給View中的一個listener賦了值。 而addListener是將該listener新增到了一個arraylsit集合裡面。 從這裡我們可以猜測,setListener只能設定一個,addListenr可以設定多個。 下面我們來看看具體。

2、測試setListener

我在xml中設定了一個按鈕
<Button
        android:id="@+id/btn_test_setListener"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="50dp"
        android:text="set測試"/>
程式碼中:
class ListenerTestActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_listener_test)
        btn_test_setListener.setOnClickListener {
            Log.e("set1", "1-listener is clicked")
        }
        btn_test_setListener.setOnClickListener {
            Log.e("set2", "2-listener is clicked")
        }
    }
}
恩, 測試demo我使用的語言是kotlin,這裡大家應該看得懂,也不復雜,也不影響結果,就不再寫一個java版本了。
可以看到,我連續設定了兩個點選事件給按鈕。
11-08 11:10:56.508 16788-16788/com.stanny.xbtest E/set2: 2-listener is clicked
11-08 11:10:57.475 16788-16788/com.stanny.xbtest E/set2: 2-listener is clicked
11-08 11:10:57.866 16788-16788/com.stanny.xbtest E/set2: 2-listener is clicked
可以看到,只有第二個點選事件被呼叫了,而第一個完全被覆蓋了。


3、測試addListener

et_test_addListener.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(p0: Editable?) {
            }

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                if (et_test_addListener.text.length == 2) {
                    Log.e("add1", "1-listener is changed")
                }
            }

        })
        et_test_addListener.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(p0: Editable?) {
            }

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                if (et_test_addListener.text.length == 2) {
                    Log.e("add2", "2-listener is changed")
                }
            }

        })
這裡我給我的輸入框添加了兩個監聽,都是在判斷輸入文字長度為2時,列印一段log
11-08 11:14:49.050 21397-21397/com.stanny.xbtest E/add1: 1-listener is changed
11-08 11:14:49.050 21397-21397/com.stanny.xbtest E/add2: 2-listener is changed

可以看到,兩個監聽,都被列印了。

4、進一步測試addListener

et_test_addListener.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(p0: Editable?) {
            }

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                if (et_test_addListener.text.length == 2) {
                    finish()//修改位置
                }
            }

        })
        et_test_addListener.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(p0: Editable?) {
            }

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                if (et_test_addListener.text.length == 2) {
                   Log.e("add2", "2-listener is changed")
                }
            }

        })
我們第一個監聽直接finish掉當前activity,那麼第二個還會執行麼
11-08 11:30:48.601 6465-6636/com.stanny.xbtest E/add2: 2-listener is changed
可以看到,即使activity已經被finish掉了,第二個監聽仍然會執行

那麼,你可能會說了,因為這兩個是同時發生的,所以才會出現仍然會執行。好,我們繼續

5、再進一步測試

et_test_addListener.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(p0: Editable?) {
            }

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                if (et_test_addListener.text.length == 2) {
                    finish()
                }
            }

        })
        et_test_addListener.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(p0: Editable?) {
            }

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                if (et_test_addListener.text.length == 2) {
                    var timer = Timer()//修改位置
                    timer.schedule(object : TimerTask() {
                        override fun run() {
                            Log.e("add2", "2-listener is changed")
                        }

                    }, 1000)
                }
            }
        })

我們給第二個監聽的列印,一個等待時間,而這時候,該activity已經被finish了
11-08 11:36:02.633 11617-11855/com.stanny.xbtest E/add2: 2-listener is changed

也是會執行的,我們的手機上,明明此時activity已經返回了上一級,但是log仍然打印出來了。

那還有沒有什麼問題?

有的,因為我們現在只是簡單的列印了文字,和當前的activity的資料或者控制元件都沒有聯絡,所以,會不會是這個原因呢?

6、最後一步測試

et_test_addListener.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(p0: Editable?) {
            }

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                if (et_test_addListener.text.length == 2) {
                    finish()
                }
            }

        })
        et_test_addListener.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(p0: Editable?) {
            }

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                if (et_test_addListener.text.length == 2) {
                    var timer = Timer()
                    timer.schedule(object : TimerTask() {
                        override fun run() {
                            Log.e("add2", "2-listener is changed")
                            btn_test_setListener.setText("123")//修改位置
                        }

                    }, 1000)
                }
            }
        })
可以看到,我在第二個延時操作的時候,不僅僅列印了log,還給一個按鈕設定了文字。

之前我們懷疑因為沒涉及到控制元件,所以不會報錯,這次,我們測試在activity被finish掉之後,對控制元件進行操作。

因為已經finish了,我們也看不到按鈕是否改變了文字,但是,我可以確定,沒有產生崩潰,沒有報錯資訊。

那麼,我們想知道,這個activity真的已經被finish掉了麼?還是說,要等到新增的監聽都實現完了才會被finish。

這個問題,等有時間,我再來研究。

相關推薦

Android開發addlistenersetlistener區別

做Android開發稍微久一點的都知道,android之前的監聽器基本都是setlistener,比如setOnClickListener,setTextChangeListener。 但是後來,android中很多的setlistener都被廢棄了,用addlistene

Android開發分析 finish() onBackPressed() 的區別

Android開發,分析 finish() 和 onBackPressed() 的區別 finish(),最常用來關閉 Actiivty 的方法。 onBackPressed(),Android 點選返回按鍵的方法。 一般來說這兩個方法作用是一致的。

Android開發 Handler RunnableThread之間的區別聯絡 應用----------------

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Android 人們口中的sdcardandroid開發中的sdcard的區別(自理解)

現在的android手機很多都不支援在手機上再插一張sdcard了,就是那種上面印著多少GB的小黑卡,我查了很多資料發現,手機自帶的記憶體(其中分為兩部分:系統所佔記憶體 + 手機除去系統所佔記憶體剩餘的記憶體,其中“手機除去系統所佔記憶體剩餘的記憶體”被安卓預設為:手機自帶

Android開發 子容器/元件在RelativeLayoutLinearLayout中居中

這裡說的是在子容器/元件中的設定。 如果父容器是 LinearLayout的話,在子容器/元件中的設定應為 android:layout_gravity="center" 如果父容器是 Relat

android gradle tools 3.X 中依賴implementation compile區別

前言 2017 年google 後,Android studio 版本更新至3.0,更新中,連帶著com.android.tools.build:gradle 工具也升級到了3.0.0,在3.0.0中使用了最新的Gralde 4.0 里程碑版本作為gradle 的編譯版

android開發http請求和https請求有什麼區別

① http效率更高,https安全性更高。 ② http是超文字傳輸協議,https是安全超文字傳輸協議, ③ http資訊是以明文方式傳遞,https是使用ssl加密傳輸協議傳輸資料,也就是通過第三方工具可以擷取篡改http傳輸的資料,而https即使截獲了沒有金鑰也白

js中decodeURI()encodeURI()區別decodeURIComponentencodeURIComponent區別

nbsp sch www 問題 encode 替換 副本 字符替換 序列 decodeURI()定義和用法:decodeURI()函數可對encodeURI()函數編碼過的URI進行解碼.語法:decodeURI(URIstring)參數描述:URIstring必需,一個字

淺談cookiesessionStoragelocalStorage區別

一次 flash htm ddb coo 清除 rem 限制 web服務器 在客戶端存儲數據可以使用的技術有如下四種: Cookie技術:瀏覽器兼容性好,但操作比較復雜,需要程序員自己封裝,源生的Cookie接口不友好 H5 WebStorage:不能超過8

Git學習筆記(三)遠程庫(GitHub)協同開發fork忽略特殊文件

tex 情況 learn 多人 版本管理 獲得 logs 秘鑰 多個 遠程庫   遠程庫,通俗的講就是不再本地的git倉庫!他的工作方式和我們本地的一樣,但是要使用他就需要先建立連接!   遠程庫有兩種,一個是自己搭建的git服務器;另一種就是使用GitHub,這個網站就是

StringStringBuilderStringBuffer區別

更改 nbsp 同步 接受 生成 blog 新的 數據轉換 法則 String字符串常量 StringBuilder 字符串變量(非線程安全) StringBuffer 字符串變量(線程安全) 1.String     String是字符串常量,為不可改變對象    

java中equalshashcode==的區別

nat 等號 bsp alt star object 名稱 改變 set 1、== java中的數據類型,可分為兩類: 1.基本數據類型,也稱原始數據類型 byte,short,char,int,long,float,double,boolean 他們之間的比較,應用雙

equals==區別 equalshashcode區別

實例對象 getc @override prime post pos bool body .get “==” : 所比較的是基本數據類型,引用變量是否相等。 “equals”:兩個獨立對象的內容是否相等。例如字符串的比較用equals String a = new

Android開發使用Retrofit發送HTTP請求

service fin tps protect convert exceptio code find content 在build.gradle(Module: app)中加入 dependencies { ... implementation ‘com.

Kotlin 繼續助力 Android 開發並計劃涉足更多領域

作者:James Lau,產品經理 今年10月3日,Kotlin 社群年度最大的現場盛會 KotlinConf 2018 舉行。2018 年是 Kotlin 的盛年,這門語言持續被採用,並贏得了大量開發者的喜愛。事實上,在 Google Play 上排名前 1000 的 And

Android開發--圓角按鈕繪製直線的實現

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Keil中translatebuildrebuild區別

在Keil程式設計環境下,有三個按鈕Translate,Build,Rebuild三個選項編譯選項。 Translate是編譯當前改動的原始檔,在這個過程中檢查語法錯誤。但並不生成可執行檔案 Build是隻編譯工程中上次修改的檔案及其它依賴於這些修改過的檔案的模組,同時重新連結生成可執

python中的幾個高階問題詳解(__init__裝飾器執行步驟@staticmethod@classmethod區別單例模式魔法方法object繼承與不繼承區別

第一個問題,init 在定義一個類時,什麼時候用__init__函式,什麼時候不用,用不用有什麼區別? 首先__init__是為了初始化用的,但是初始化的時候不一定要用這個,直接定義也是可以的,比如 class A(object): test_a = '123' 而我們用__

Android開發測試機不列印Log的解決辦法

在Android開發過程中,使用某些真機測試 App 時,發現 LogCat 控制檯不顯示輸出的Log。 百度谷歌一番之後,發現原因竟然是國內的部分廠商深度定製的Android系統,對於應用中的 Log 日誌預設做了列印限制,需要手動設定才能打印出日誌。測試了幾部手機,發現魅族和華為手機有這

初學Android開發用eclipse新建helloworld時出現失敗

初學Android開發,用eclipse新建helloworld時出現失敗 報錯資訊 解決方案 報錯資訊 [2018-12-02 10:40:39 - ad_hello] E:\eclipse-workspace\ad_hello\res\v