Kotlin学习笔记_延迟初始化和密封类

Kotlin学习笔记_延迟初始化和密封类

  • 延迟初始化
    • 延迟初始化的使用
    • 判断是否完成初始化
  • 密封类
    • Result接口
    • getResultMsg()方法
    • 密封类的基本使用
    • 优化MsgAdapter中的代码
      • MsgViewHolder.kt
      • MsgAdapter
  • 参考

延迟初始化

延迟初始化的使用

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?

虽然adapter会在onCreate()方法中被初始化, 且能确保onClick()方法必然在onCreate()方法之后才会调用, 但是在onClick()方法中调用adapter的任何方法时仍然要进行判空处理, 否则无法通过编译.

当代码中的全局变量实例越来越多时, 为了满足Kotlin编译器的要求, 需要编写大量额外的判空处理代码.

可以通过延迟初始化来解决这个问题.
延迟初始化使用lateinit关键字, 代码如下:

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关键字, 就可以不用初始化为null, 同时类型声明也可以改成MsgAdapter. 因为MsgAdapter是非空类型, 所以在onClick()方法中也就不需要判空处理了.

在adapter没有初始化的情况下使用, 程序会抛UninitializedPropertyAccessException异常.

判断是否完成初始化

class MainActivity : AppCompatActivity(), View.OnClickListener {

    private lateinit var adapter: MsgAdapter 

    override fun onCreate(savedInstanceState: Bundle?) { 
        ... 
        if (!::adapter.isInitialized) { 
            adapter = MsgAdapter(msgList) 
        } 
        ... 
    } 

} 

::adapter.isInitialized用于判断变量是否已经初始化. !对结果取反, 若没有初始化, 则进行初始化.

密封类

Result接口

interface Result
class Success(val msg: String) : Result
class Failure(val error: Exception) : Result

getResultMsg()方法

fun getResultMsg(result: Result){
    when(result)
    {
        is Success -> result.msg
        is Failure -> result.error.message
        else -> throw IllegalArgumentException()
    }
}

else分支是为了满足Kotlin编译器的语法检查, 没有else分支的话, Kotlin编译器会认为条件缺失, 无法编译.

当新增一个Unknown类并实现Result接口, 用于表示未知的执行结果, 但是忘记在getResultMsg()方法中添加对应的条件分支, 编译器在这种情况下不会提醒, 而是进入else分支.(在其他编程语言也普遍存在)

密封类的基本使用

// 密封类及其所有子类只能定义在同一个文件的顶层位置,不能嵌套在其他类中,这是被密封类底层的实现机制所限制的。
sealed class Result
class Success(val msg: String) : Result()
class Failure(val error: Exception) : Result()

fun getResultMsg(result: Result){
    
    // 当when语句传入一个密封类变量时, Kotlin编译器会自动检查该密封类有哪些子类, ->
    // ->并强制要求将所有子类对应的条件处理.这样就不会漏写条件分支.
    when(result)
    {
        is Success -> result.msg
        is Failure -> result.error.message
    }
}

优化MsgAdapter中的代码

MsgViewHolder.kt

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)
}

MsgAdapter

class MsgAdapter(val msgList: List<Msg>) : RecyclerView.Adapter<MsgViewHolder>() {
    ...
    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
        }
    }
    ...
}

参考

郭霖. 《第一行代码 Android 第3版》

你可能感兴趣的:(kotlin,kotlin,android,学习,java,android,studio)