RecyclerView基本使用 中最后 MainActivity 中
class MainActivity : AppCompatActivity(),View.OnClickListener {
...
private var adapter: MsgAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
...
adapter = MsgAdapter(msgList)
...
}
....
override fun onClick(v: View?) {
...
adapter?.notifyItemInserted(msgList.size-1)
...
}
}
我们将 adapter 设置成了全局变量,但它的初始化是在 onCreate() 方法中进行的,因此不得不先将 adapter 赋值 null,并且把它的类型声明成 MsgAdapter?
虽然我们会在 onCreate() 中对 adapter 进行初始化,同时能确保 onClick() 方法必然在 onCreate() 后才会调用,但我们在 onClick() 方法中调用 adaper 的任何方法时仍然要进行判空处理才行,否则编译无法通过
这个问题我们可以对全局变量进行延迟初始化。使用关键字lateinit
,它告诉编译器,我会在晚些时候对这个变量进行初始化,这样就不用在一开始赋值为 null 了
class MainActivity : AppCompatActivity(),View.OnClickListener {
...
private lateinit var adapter: MsgAdapter
override fun onCreate(savedInstanceState: Bundle?) {
...
adapter = MsgAdapter(msgList)
...
}
....
override fun onClick(v: View?) {
...
adapter.notifyItemInserted(msgList.size-1)
...
}
}
当然,使用lateinit
也是有风险的,如果我们在 adapter 变量还没初始化的情况下就直接使用它,那么程序一定崩溃。所以一定要确保它在被任何地方调用之前已经完成了初始化工作。我们可以通过代码来判断一个全局变量是否已经完成了初始化,这样在某些时候能有效避免重复对一个变量进行初始化:
class MainActivity : AppCompatActivity(),View.OnClickListener {
...
private lateinit var adapter: MsgAdapter
override fun onCreate(savedInstanceState: Bundle?) {
...
if(!::adapter.isInitialized){
adapter = MsgAdapter(msgList)
}
...
}
....
override fun onClick(v: View?) {
...
adapter.notifyItemInserted(msgList.size-1)
...
}
}
新建一个 Result.kt
interface Result
class Success(val msg: String) : Result
class Failure(val error: Exception) : Result
fun getResultMsg(result: Result) = when(result) {
is Success -> result.msg
is Failure -> result.error.message
else -> throw IllegalArgumentException()
}
这里定义了一个 Result 接口,然后定义了两个类去实现 Result 接口。然后再写一个 getResultMsg() 方法。实际上 Result 的执行结果只能是 Success 或 Failure,所以里边的 else 永远无法走到,但我们不得不写上,只是为了满足 Kotlin 编译器的语法检查而已
密封类可以帮我们解决这个问题,使用关键字 sealed class
sealed class Result
class Success(val msg: String) : Result()
class Failure(val error: Exception) : Result()
fun getResultMsg(result: Result) = when(result) {
is Success -> result.msg
is Failure -> result.error.message
}
代码太大变化,只是将 interface
改成了 sealed class
,另外由于密封类是一个可继承的类,因此在继承它的时候需要加上一对括号,你会发现 getResultMsg() 方法中的 else 已经不需要了。因为当 when 语句传入一个密封类变量作为条件时,Kotlin 编译器会自动检查该密封类有哪些子类,并强制要求你将每一个子类所对应的条件全部处理
接下来我们可以用这个知识点优化 RecyclerView基本使用 中 MsgAdapter 中的代码了
sealed class MsgViewHolder(view:View): RecyclerView.ViewHolder(view)
class LeftViewHolder(view:View):MsgViewHolder(view){
val leftMsg: TextView = view.findViewById(R.id.leftMsg)
}
class RightViewHolder(view:View):MsgViewHolder(view){
val rightMsg: TextView = view.findViewById(R.id.rightMsg)
}
class MsgAdapter(val msgList: List<Msg>):RecyclerView.Adapter<MsgViewHolder> (){
override fun getItemViewType(position: Int): Int {
return msgList[position].type
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MsgViewHolder =
if (viewType == Msg.TYPE_RECEIVED){
val view = LayoutInflater.from(parent.context).inflate(R.layout.msg_left_item,parent,false)
LeftViewHolder(view)
}else{
val view = LayoutInflater.from(parent.context).inflate(R.layout.msg_right_item,parent,false)
RightViewHolder(view)
}
override fun onBindViewHolder(holder: MsgViewHolder, position: Int) {
val msg = msgList[position]
when(holder){
is LeftViewHolder -> holder.leftMsg.text = msg.content
is RightViewHolder -> holder.rightMsg.text = msg.content
}
}
override fun getItemCount(): Int = msgList.size
}