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 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方法: