Kotlin的lazy属性委托可以实现对属性的懒加载,但是只能使用于不可变属性,当属性需要重新加载时即无法使用,编写了一个resettablelazy,在满足懒加载的同时,也能在适当时机对属性进行重置,让属性在重置后的下次调用重新加载

基本概念

by关键字在kotlin中称为属性委托,指将某个属性托付给一个代理类进行实现,这个属性的get和set方法由代理类的getValue()setValue()方法
kotlin官方文档中的委托属性的相的模板:

import kotlin.reflect.KProperty

class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}

operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to '${property.name}' in $thisRef.")
}
}

再进入kotlin的源码查看lazy的具体实现

public actual fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)

可以看到lazy返回了一个SynchronizedLazyImpl类的对象,进入SynchronizedLazyImpl:

private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {
private var initializer: (() -> T)? = initializer
@Volatile private var _value: Any? = UNINITIALIZED_VALUE
// final field is required to enable safe publication of constructed instance
private val lock = lock ?: this

override val value: T
get() {
val _v1 = _value
if (_v1 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST")
return _v1 as T
}

return synchronized(lock) {
val _v2 = _value
if (_v2 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST") (_v2 as T)
} else {
val typedValue = initializer!!()
_value = typedValue
initializer = null
typedValue
}
}
}

override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE

override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."

private fun writeReplace(): Any = InitializedLazyImpl(value)
}

在SynchronizedLazyImpl中有一个不可变属性value,在value的get方法中通过判断保持返回对象的唯一性

结合使用lazy,即保持lazy的线程安全特性也保证了可重置

代码:

class ResettableLazy<PROPTYPE>(val init: () -> PROPTYPE) {

var lazyHolder = makeInitBlock()

operator fun getValue(thisRef: Any?, property: KProperty<*>): PROPTYPE {
return lazyHolder.value
}

fun isInitialized(): Boolean {
return lazyHolder.isInitialized()
}

fun reset() {
lazyHolder = makeInitBlock()
}

fun makeInitBlock(): Lazy<PROPTYPE> {
return lazy {
init()
}
}
}

fun <PROPTYPE> resettableLazy(init: () -> PROPTYPE): ResettableLazy<PROPTYPE> {
return ResettableLazy(init)
}

使用

使用时还是使用by
eg:

private val sdfLazy = resettableLazy {
SimpleDateFormat.getDateTimeInstance(
SimpleDateFormat.MEDIUM, SimpleDateFormat.SHORT, Locale.getDefault())
}
private val sdf: DateFormat by sdf1Lazy

重置调用调用托管类的reset方法:

sdf1Lazy.reset()