面试中被问到,使用kotlin的时候,如何实现监听,例如点击事件:
首先,平常开发中,Kotlin在使用期间,我们的习惯是使用已经熟悉的事务,初次听到这个的时候,有一些懵,
回答说,正常写一个interface,传一个position:Int?,一个any:Any?,实际上,这样的listener已经能面对很多
情况下的监听了,当然面试官需要的不是这样的答案,
所以,被问到,有没有用到过invoke来实现监听?
没有!!!
回程后查阅资料,大部分写的是「Kotlin自定义监听」
以下为基本代码,
正常的RecyclerView中的Adapter:
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.qiufeng.myapplication.R
import kotlinx.android.synthetic.main.item_main.view.*
class MainItemAdapter(
private val context: Context,
private val items: Array<String>
) : RecyclerView.Adapter<MainItemAdapter.NormalViewHolder>() {
inner class NormalViewHolder(view: View) : RecyclerView.ViewHolder(view)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NormalViewHolder {
val view = LayoutInflater.from(context.applicationContext)
.inflate(R.layout.item_main, parent, false)
return NormalViewHolder(view)
}
override fun getItemCount(): Int = items.size
override fun onBindViewHolder(holder: NormalViewHolder, position: Int) {
holder.itemView.tv_title.text = items[position]
holder.itemView.setOnClickListener{
if (::onViewClick.isInitialized)onViewClick.invoke(position)
}
}
lateinit var onViewClick: (position:Int) ->Unit// 无参 括号中不写
}
实际调用MainActivity.java
val adapter = MainItemAdapter(this, arrayOf("1", "2", "3", "4", "5", "6"))
rv_list.adapter = adapter
rv_list.layoutManager = LinearLayoutManager(this)
adapter.onViewClick = {
println("当前点击到:".plus(it))
}
看到代码中没有关于adapter相关Listener的set方法,可是调用的时候却异常简单,
实际上可以理解为在Activity中获取到Adapter 对象之后,对onViewClick变量赋值,值为一个函数,
如此实现,确实可以省略开发中一些代码,也可以随时修改参数,毕竟没有固定Listener,所以不必担心会
影响其它的调用者,当然,如果有的时候追求Utils编码,还是可以写成Listener,只是在代码量上,确实invoke
过于简便,想了下,应该完全替代任何监听了,当然参数不会超过22个吧
adapter 中变量声明,对应使用方法
// lateinit 写法 A
lateinit var onViewClick: (position: Int) -> Unit
// null 写法 B
var onViewClick0: ((position: Int) -> Unit)? = null
// 无参 null 写法 C
var onViewClick1: (() -> Unit)? = null
// Adapter中调用
holder.itemView.setOnClickListener {
// 对应lateinit var,这种写法安全
if (::onViewClick.isInitialized) onViewClick.invoke(position)
// 这种写法对应lateinit var不安全,如果没有调用会崩溃,
// 涉及到声明方式
onViewClick.invoke(position)
// 对应 B
onViewClick0?.invoke(position)
// 对应 C
onViewClick1?.invoke()
}
推荐 写法:B、C
lateinit var声明的变量,必须经历初始化后再用,本身Kotlin就是避免空指针,个人感觉lateinit var在一定程度上违反了这一原则,毕竟不会编译报错