lambda 和 高階函數
碾子山網站建設公司創新互聯公司,碾子山網站設計制作,有大型網站制作公司豐富經驗。已為碾子山成百上千家提供企業網站建設服務。企業網站搭建\外貿網站建設要多少錢,請找那個售后服務好的碾子山做網站的公司定做!
之前學習了 lambda 和高階函數,然后在 android 開發中對 onClick 事件進行監聽是一個很常用的功能,kotlin 的常規實現如下:
rootView.setOnClickListener { view -> println("點擊了這個ID=${view.id}的view") }
然后在開發中不可避免的我們也要寫一些自定義監聽之類的代碼。這個時候如果還用 java 的思想去實現的話就有點舍近求遠了。
java 思想實現
在 java 中我們一般的做法是這樣的
定義一個接口
定義一個接口類型變量
定義一個 set 方法
調用 set 方法設置接口的實現類
用 kotlin 實現就是如下
class MyView{ //定義一個接口 interface IOnLabelCheckedListener { fun onLabelCheck(label: String) } //定義一個接口類型變量 private var onLabelChecked: IOnLabelCheckedListener? = null private fun initView(context: Context) { view.setOnCheckedChangeListener { radioGroup, i -> onLabelChecked.onLabelCheck(radioGroup.findViewById<RadioButton>(i).text.toString()) } } //定義一個 set 方法 fun setOnLabelCheckedListener(e: IOnLabelCheckedListener) { this.onLabelChecked = e } } // 調用set方法,通過匿名內部類實現 MyView.setOnLabelCheckedListener(object : LabelBarView.IOnLabelCheckedListener { override fun onLabelCheck(label: String) { } })
這樣實現的問題
當然是太復雜了。而且最初的時候這樣寫一時搞不明白為什么 MyView.setOnLabelCheckedListener 方法內部不能傳入 lambda 表達式,lambda 表達式的存在不就是為了替代匿名內部類嘛。而且如果這個接口定義的是一個 java 類型的接口就是可以用 lambda 表達式的。這是為什么?最后猜想是因為 kotlin 在和 java 互相調用的時候中間又包裹了一層,而我們直接使用 kotlin 來定義這個接口不存在中間這一層,而我們定義的 set 方法又不是一個高階函數,當然不能使用 lambda 表達式。
下面就用 kotlin 的思想來實現回調
使用高階函數來實現
kotlin 和 java 有一個重要的不同就是函數式編程。在函數式編程的思想中函數是一等公民,在使用 kotlin 時我們要多利用這種思維來思考問題。Kotlin 中提供了高階函數,它可以直接使用一個函數來作為返回值,對于習慣于 java 來編程的我來說剛開始理解起來有些困難,下面我把我一步一步的實現一個高階函數的思路寫下,希望對大家有所幫助。
首先,能想到的就是函數傳遞,要用 lambda 來替代掉匿名內部類可以這樣來實現
//從最基礎的開始做,把匿名內部類通過 lambda 實現 MyView.setOnLabelCheckedListener(object : MyView.IOnLabelCheckedListener { override fun onLabelCheck(label: String) { println(label) } }) // 首先 MyView.IOnLabelCheckedListener 中只有一個方法 onLabelCheck(label: String) // 因此可以寫出 lambda 表達式如下 var lam: (String) -> Unit = { label -> println(label) }
然后,需要把寫好的 lambda 傳遞進去,這個時候就要求 setOnLabelCheckedListener 方法是一個高階函數
// 這里接收一個 上面我們改造好的表達式 lam ,它內部實現應該是把 e 賦值給當前類的一個對象 fun setOnLabelCheckedListener(e: (String) -> Unit) { this.lisenter = e } //顯然 lisenter 就應該是這樣的 var linsnter: (String) -> Unit = {}
最后使用 linsnter 進行回調
private fun initView(context: Context) { view.setOnCheckedChangeListener { radioGroup, i -> linsnter(radioGroup.findViewById<RadioButton>(i).text.toString()) } }
最終代碼結果:
class MyView{ var linsnter: (String) -> Unit = {} private fun initView(context: Context) { view.setOnCheckedChangeListener { radioGroup, i -> linsnter(radioGroup.findViewById<RadioButton>(i).text.toString()) } } fun setOnLabelCheckedListener(e: (String) -> Unit) { this.lisenter = e } } // 調用時將變量 lam 省略,直接使用一個表達式 view.setOnLabelCheckedListener { label -> println(label) }
最終的代碼和之前的代碼有兩個最大的不同,一是沒有了接口定義,二是沒有了匿名內部類。
更好的使用高階函數
高階函數的使用更多的時候能使我們的代碼更簡潔,比如下面這段代碼:
fun refreshData(e: ((Boolean, String) -> Unit)): Boolean { if (!UserInfoManager.getInstance().isLogin) { e(false, "未登錄") return false } NETWorkUtils.request(ApiParamter(), object : ApiListener<ResponseData> { override fun onApiCompleted(data: ResponseData?) { e(true, "成功") } override fun onApiError(errorCode: Int, errorCodeMessage: String) { e(false, errorCodeMessage) } }) return true }
那么在調用它的時候就可以這樣:
mView.refreshData { isSuccess, msg -> //do something }
是不是很簡單,省去了再寫一個接口。同時如果是用 java 來調用 refreshData 方法也一樣可以的:
mView.refreshData(new Function2<Boolean, String, Unit>() { @Override public Unit invoke(Boolean aBoolean, String s) { // do something return null; } });
Kotlin 提供了一系列的 Function 接口類來供 java 調用高階函數時使用,最多支持22個參數有興趣的可以查看一下。
以上就是在 Kotlin 中使用高階函數來替代傳統的回調函數的方法。不對之處還請指正。希望能給大家一個參考,也希望大家多多支持創新互聯。
當前標題:Kotlin使用高階函數實現回調方式
文章位置:http://vcdvsql.cn/article26/pepccg.html
成都網站建設公司_創新互聯,為您提供企業建站、Google、手機網站建設、關鍵詞優化、小程序開發、移動網站建設
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯