【kotlin】延迟初始化和密封类

文章目录

  • 延迟初始化
  • 使用密封类优化代码

延迟初始化

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
}

你可能感兴趣的:(Kotlin从零到一无所有,kotlin)