一個setOnClickListener的錯誤
寫了個demo返劲,點擊事件離奇的不生效唉窃,非常困擾剪菱。
開始實在是看不出有什么問題摩瞎,錯誤代碼如下:
findViewById<Button>(R.id.btn).setOnClickListener {
View.OnClickListener {
...
}
}
運行不報錯,就是不觸發(fā)OnClickListener中的代碼孝常。
那么正確的寫法應(yīng)該是怎樣呢愉豺?
如下所示:
// 寫法1:OnClickListener寫法
findViewById<Button>(R.id.btn).setOnClickListener(
View.OnClickListener {
...
}
)
或者這樣:
// 寫法2:閉包寫法
findViewById<Button>(R.id.btn).setOnClickListener {
...
}
為什么那個錯誤的寫法不報錯但是卻不能正確運行呢?
因為錯誤的寫法實際上是在寫法2的閉包里面又聲明了一個OnClickListener茫因,僅僅聲明listener當然不能調(diào)用里面的代碼了。
將函數(shù)作為參數(shù)傳遞
為什么setOnClickListener
有兩種寫法呢杖剪?
實際上這里setOnClickListener
這個方法有兩個重載:
// 參數(shù)是OnClickListener對象
fun setOnClickListener(l: View.OnClickListener?)
// 參數(shù)是閉包
fun setOnClickListener(l: (v: View) -> Unit)
因為有兩個重載方法冻押,setOnClickListener
才可以有兩種寫法。
所謂閉包:
在計算機科學(xué)中盛嘿,閉包(英語:Closure)洛巢,又稱詞法閉包(Lexical Closure)或函數(shù)閉包(function closures),是引用了自由變量的函數(shù)次兆。這個被引用的自由變量將和這個函數(shù)一同存在稿茉,即使已經(jīng)離開了創(chuàng)造它的環(huán)境也不例外。
kotlin中的閉包一般稱為lambda表達式芥炭,詳細內(nèi)容可以查看:
我們這里只看將函數(shù)作為參數(shù)傳遞的用法漓库。
因為閉包這一特性的存在,上面setOnClickListener
才可以不使用傳統(tǒng)的OnClickListener
园蝠, 下面我們自己定義一個簡單的例子來說明渺蒿。
傳統(tǒng)寫法:
// 聲明listener
interface TestListener {
fun test()
}
// 聲明使用listener作為參數(shù)的方法
private fun setListener(listener: TestListener) {
// 調(diào)用listener的test方法
listener.test()
}
// 方法中使用
fun main(){
setListener(object : TestListener {
override fun test() {
Log.i("test_tag", "test Listener")
}
})
}
閉包寫法:
// 聲明方法
private fun setListener(listener: () -> Unit) {
// 調(diào)用傳入的方法
listener()
}
// 方法中使用
fun main(){
setListener { Log.i("test_tag", "test unit") }
}
明顯簡化了許多,再也不需要通過聲明接口設(shè)置監(jiān)聽了彪薛。
需要額外說明將函數(shù)作為參數(shù)傳遞使用的幾種變種:
帶參數(shù)的閉包:
// 帶參數(shù)
private fun setListener(l: (c: Context) -> Unit) {
l(applicationContext)
}
// 使用茂装,只有一個參數(shù)時,可以用it代替?zhèn)魅氲膮?shù)
setListener { Toast.makeText(it, "test param", Toast.LENGTH_SHORT).show() }
帶參數(shù)且有返回值:
private fun setListener(l: (c: Context) -> Boolean) {
val b = l(applicationContext)
Toast.makeText(applicationContext, if (b) "當前時間是偶數(shù)" else "當前時間是奇數(shù)", Toast.LENGTH_SHORT).show()
}
// 使用善延,只有一個參數(shù)時少态,可以用it代替?zhèn)魅氲膮?shù)
setListener {
Toast.makeText(it, "test param", Toast.LENGTH_SHORT).show()
// 當前時間是否是偶數(shù)
System.currentTimeMillis() % 2 == 0L
}