Kotlin 使用高阶函数实现回调方式
lambda和高阶函数
之前学习了lambda和高阶函数,然后在android开发中对onClick事件进行监听是一个很常用的功能,kotlin的常规实现如下:
rootView.setOnClickListener{view-> println("点击了这个ID=${view.id}的view") }
然后在开发中不可避免的我们也要写一些自定义监听之类的代码。这个时候如果还用java的思想去实现的话就有点舍近求远了。
java思想实现
在java中我们一般的做法是这样的
定义一个接口
定义一个接口类型变量
定义一个set方法
调用set方法设置接口的实现类
用kotlin实现就是如下
classMyView{ //定义一个接口 interfaceIOnLabelCheckedListener{ funonLabelCheck(label:String) } //定义一个接口类型变量 privatevaronLabelChecked:IOnLabelCheckedListener?=null privatefuninitView(context:Context){ view.setOnCheckedChangeListener{radioGroup,i-> onLabelChecked.onLabelCheck(radioGroup.findViewById(i).text.toString()) } } //定义一个set方法 funsetOnLabelCheckedListener(e:IOnLabelCheckedListener){ this.onLabelChecked=e } } //调用set方法,通过匿名内部类实现 MyView.setOnLabelCheckedListener(object:LabelBarView.IOnLabelCheckedListener{ overridefunonLabelCheck(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{ overridefunonLabelCheck(label:String){ println(label) } }) //首先MyView.IOnLabelCheckedListener中只有一个方法onLabelCheck(label:String) //因此可以写出lambda表达式如下 varlam:(String)->Unit={label->println(label)}
然后,需要把写好的lambda传递进去,这个时候就要求setOnLabelCheckedListener方法是一个高阶函数
//这里接收一个上面我们改造好的表达式lam,它内部实现应该是把e赋值给当前类的一个对象 funsetOnLabelCheckedListener(e:(String)->Unit){ this.lisenter=e } //显然lisenter就应该是这样的 varlinsnter:(String)->Unit={}
最后使用linsnter进行回调
privatefuninitView(context:Context){ view.setOnCheckedChangeListener{radioGroup,i-> linsnter(radioGroup.findViewById(i).text.toString()) } }
最终代码结果:
classMyView{ varlinsnter:(String)->Unit={} privatefuninitView(context:Context){ view.setOnCheckedChangeListener{radioGroup,i-> linsnter(radioGroup.findViewById(i).text.toString()) } } funsetOnLabelCheckedListener(e:(String)->Unit){ this.lisenter=e } } //调用时将变量lam省略,直接使用一个表达式 view.setOnLabelCheckedListener{label-> println(label) }
最终的代码和之前的代码有两个最大的不同,一是没有了接口定义,二是没有了匿名内部类。
更好的使用高阶函数
高阶函数的使用更多的时候能使我们的代码更简洁,比如下面这段代码:
funrefreshData(e:((Boolean,String)->Unit)):Boolean{ if(!UserInfoManager.getInstance().isLogin){ e(false,"未登录") returnfalse } NETWorkUtils.request(ApiParamter(),object:ApiListener{ overridefunonApiCompleted(data:ResponseData?){ e(true,"成功") } overridefunonApiError(errorCode:Int,errorCodeMessage:String){ e(false,errorCodeMessage) } }) returntrue }
那么在调用它的时候就可以这样:
mView.refreshData{isSuccess,msg-> //dosomething }
是不是很简单,省去了再写一个接口。同时如果是用java来调用refreshData方法也一样可以的:
mView.refreshData(newFunction2(){ @Override publicUnitinvoke(BooleanaBoolean,Strings){ //dosomething returnnull; } });
Kotlin提供了一系列的Function接口类来供java调用高阶函数时使用,最多支持22个参数有兴趣的可以查看一下。
以上就是在Kotlin中使用高阶函数来替代传统的回调函数的方法。不对之处还请指正。希望能给大家一个参考,也希望大家多多支持毛票票。