有如下常用情景,在某个Adapter我们设置自己的接口回调,将原来的java代码改写之后大概会是这个样子:
class SomeListAdapter(){ var mOnItemClickListener:OnItemClickListener? = null fun setOnItemClickListener(onItemClickListener : OnItemClickListener){ mOnItemClickListener = onItemClickListener } override fun onBindViewHolder(holder: RecyclerView.ViewHolder?, position: Int) { mOnItemClickListener?.onItemClick(article) } companion object { public interface OnItemClickListener{ fun onItemClick(article:DTArticle) } }}//override fun setAdapter(){ var adapter = SomeListAdapter(context) adapter.setOnItemClickListener ( object: ArticleListAdapter.Companion.OnItemClickListener { override fun onItemClick(article: DTArticle) { SomeDetailActivity.startInstance(context,article.mId) } } )}
即使你完全不知道kotlin,也很容易理解上面的代码,因为和java实在是太像了。
但是对于kotlin而言,或许我们有更好更简单的方法
class SomeListAdapter(context: Context) : BaseListAdapter(context) { lateinit var mOnItemClickListener: (DTArticle) -> Unit fun setOnItemClickListener(onItemClickListener: (DTArticle) -> Unit) { mOnItemClickListener = onItemClickListener } override fun onBindViewHolder(holder: RecyclerView.ViewHolder?, position: Int) { if (mOnItemClickListener != null) { mOnItemClickListener(article) } } companion object { }}//override fun setAdapter(){ var adapter = SomeListAdapter(context) adapter.setOnItemClickListener{ SomeDetailActivity.startInstance(context,it.mId) }}
看看我们做了什么?我们抛弃了接口的概念,而是引入了一个新的类型的变量:
(DTArticle) -> Unit
这是一个整体,不可分割,表示入参是DTArticle,返回值为空的一个方法参数,有点类似函数指针的样子嘛。
注意,调用的地方也有所改变,我们需要意识到,这个参数本身就是一个方法。
能不能继续简化?多谢一个setOnItemClickListener感觉在kotlin中是没必要的,所以,我们去掉它吧
class SomeListAdapter(context: Context) : BaseListAdapter(context) { lateinit var mOnItemClickListener: (DTArticle) -> Unit override fun onBindViewHolder(holder: RecyclerView.ViewHolder?, position: Int) { if (mOnItemClickListener != null) { mOnItemClickListener(article) } } companion object { }}//override fun setAdapter(){ var adapter = SomeListAdapter(context) adapter.mOnItemClickListener = { SomeDetailActivity.startInstance(context,it.mId) }}
这样就看上去很简洁了,并且已经和java代码相去胜远了,但是实际上做的是同一件事情。
对于多参数的接口类型,比如:
lateinit var listener:(pos:Int,a:String)->Unit
会出现一个问题,it到底代指哪个参数?肯定会出现问题,所以对于这种情况,使用时这样的
listener = {pos, a -> Log.d("sss",a+pos) }
我们需要显示的指定参数名!