kotlin中声明属性的时候是要要求初始化的,否则就会编辑器就会报错,但是在开发中我们并不是立即初始化属性,比如定义控件名称的时候,我们不会在定义时就fingViewById来初始化控件,而是在页面生命周期函数里面来初始化控件。kotlin为开发者们提供了延迟初始化的方案。
接下来让我们讲讲kotlin中两种延迟初始化的技术
lateinit
看看例子
class AttriKotlin {
//val song :Int//Property must be initialized or be abstract
val song :Int = 0
var biao :String = "biao"
}
在上面的例子中我们可以到编辑器报错的内容是指该属性必须初始化或者抽象。我们没必要抽象又想不立即初始化,所以让我们看看用上lateinit
class AttriKotlin {
//'lateinit' modifier is not allowed on properties of primitive types
lateinit var song:Int
//'lateinit' modifier is not allowed on properties of nullable types
lateinit var song:String?
lateinit var biao:String//这样子是ok的
}
从上面例子中可以看到lateinit不能修饰基本数据类型,也不能修饰可为空的属性,原因在于Kotlin会使用null来对每一个用lateinit修饰的属性做初始化,而基础类型是没有null类型,所以无法使用lateinit。
再来项目中经常需要用到的,eg
class lazyClass(): Activity() {
lateinit var textView:TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
textView = findViewById(R.id.getEdit_btn)
}
}
小结:
- lateinit只能用于var,所以经常是lateinit var连用
- lateinit只能用来修饰类属性,不能用来修饰局部变量
- lateinit不能修饰基本数据类型,如果int(kotlin基本类型:Double、Int、Float、Long、Short、Byte)
- lateinit用于只能生命周期流程中进行获取或者初始化的变量,比如 Android 的 onCreate()
by lazy
延迟加载有几个好处。首先由于加载时机推迟到了变量被访问时,因此它可以提高应用的启动速度。相比于使用 Kotlin 开发服务端应用,这一特性对开发 Android 应用而言特别有用。对于 Android 应用来说,我们想要减少应用启动时间,这样用户可以更快看到应用的内容,而不是干等着看启动加载页面。
其次,这样的延迟加载也有更高的内存效率,因为我们只在它被调用时才将资源加载进内存。在 Android 这样的移动平台上,内存的使用是非常重要的。因为手机资源是共享的且有限的。
延迟加载也是封装初始化逻辑的好方法:
val views: RectF by lazy {
RectF(0f, 0f, width.toFloat(), height.toFloat())
}
只有当 bounds 变量第一次被引用时,将会使用 view 的当前宽和高的值来创建 RectF,这样我们就不需要一开始显式的创建 RectF,然后把它设置给 views。
- lazy只能修饰val
- 应用于单例模式(if-null-then-init-else-return),而且当且仅当变量被第一次调用的时候,委托方法才会执行。
eg:
//by lazy是单例模式的(if null init else return),而且当且仅当变量第一次被初始化时,委托方法(by lazy)才会被调用
val name by lazy {
println("只调用一次")
"biao"
}
val lazyClass = LazyClass()
val name = lazyClass.name
val name1 = lazyClass.name
println("lazy-name:$name")
println("lazy-name:$name1")
result:
只调用一次
lazy-name:biao
lazy-name:biao
从上面例子可以看出属性name在第一次被调用的时候走了委托方法去初始化,之后都是拿属性的getter
eg:
class LazyClass: Activity() {
//kotlin 封装:
fun <V : View> Activity.bindView(id: Int): Lazy<V> = lazy {
viewFinder(id) as V
}
//acitivity中扩展调用
private val viewFinder: Activity.(Int) -> View?
get() = { findViewById(it) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//在activity中的使用姿势
val mTextView by bindView<TextView>(R.id.edit_query)
mTextView.text="执行到我时,才会进行控件初始化"
}
}