Kotlin懒惰属性和值重置:一个可重置的懒惰委托

所以我使用android的kotlin ,当充气的意见,我倾向于做到以下几点:

 private val recyclerView by lazy { find<RecyclerView>(R.id.recyclerView) } 

这种方法将起作用。 但是,有一种情况会对应用程序造成影响。 如果这是一个片段,并且片段进入了后台, onCreateView将被再次调用,并且片段的视图层次将被重新创建。 这意味着懒惰启动的recyclerView将指向不再存在的旧视图。

解决方案是这样的:

 private lateinit var recyclerView: RecyclerView 

并初始化onCreateView内的所有属性。

我的问题是,是否有任何方法来重置懒惰属性,以便他们可以再次初始化? 我喜欢初始化都是在一个类的顶部完成,有助于保持代码的组织。 具体的问题是在这个问题中发现: 回收后kotlin android碎片空回收站视图

这是一个可重置的懒惰的快速版本,它可以更优雅,需要双重检查线程安全性,但这基本上是这个想法。 你需要管理(跟踪)懒惰代表的东西,所以你可以调用重置,然后可以管理和重置的东西。 这在这些管理类中包装lazy()

下面是你最后一堂课的样子

 class Something { val lazyMgr = resettableManager() val prop1: String by resettableLazy(lazyMgr) { ... } val prop2: String by resettableLazy(lazyMgr) { ... } val prop3: String by resettableLazy(lazyMgr) { ... } } 

然后,让懒人在下次访问时回到新值:

 lazyMgr.reset() // prop1, prop2, and prop3 all will do new lazy values on next access 

可重置懒惰的执行:

 class ResettableLazyManager { // we synchronize to make sure the timing of a reset() call and new inits do not collide val managedDelegates = LinkedList<Resettable>() fun register(managed: Resettable) { synchronized (managedDelegates) { managedDelegates.add(managed) } } fun reset() { synchronized (managedDelegates) { managedDelegates.forEach { it.reset() } managedDelegates.clear() } } } interface Resettable { fun reset() } class ResettableLazy<PROPTYPE>(val manager: ResettableLazyManager, val init: ()->PROPTYPE): Resettable { @Volatile var lazyHolder = makeInitBlock() operator fun getValue(thisRef: Any?, property: KProperty<*>): PROPTYPE { return lazyHolder.value } override fun reset() { lazyHolder = makeInitBlock() } fun makeInitBlock(): Lazy<PROPTYPE> { return lazy { manager.register(this) init() } } } fun <PROPTYPE> resettableLazy(manager: ResettableLazyManager, init: ()->PROPTYPE): ResettableLazy<PROPTYPE> { return ResettableLazy(manager, init) } fun resettableManager(): ResettableLazyManager = ResettableLazyManager() 

还有一些单元测试可以肯定:

 class Tester { @Test fun testResetableLazy() { class Something { var seed = 1 val lazyMgr = resettableManager() val x: String by resettableLazy(lazyMgr) { "x ${seed}" } val y: String by resettableLazy(lazyMgr) { "y ${seed}" } val z: String by resettableLazy(lazyMgr) { "z $x $y"} } val s = Something() val x1 = sx val y1 = sy val z1 = sz assertEquals(x1, sx) assertEquals(y1, sy) assertEquals(z1, sz) s.seed++ // without reset nothing should change assertTrue(x1 === sx) assertTrue(y1 === sy) assertTrue(z1 === sz) s.lazyMgr.reset() s.seed++ // because of reset the values should change val x2 = sx val y2 = sy val z2 = sz assertEquals(x2, sx) assertEquals(y2, sy) assertEquals(z2, sz) assertNotEquals(x1, x2) assertNotEquals(y1, y2) assertNotEquals(z1, z2) s.seed++ // but without reset, nothing should change assertTrue(x2 === sx) assertTrue(y2 === sy) assertTrue(z2 === sz) } } 

我有同样的任务,这就是我使用的:

 import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KProperty class SingletonLazy<T : Any>(val initBlock: () -> T, val clazz: Class<T>) { operator fun <R> provideDelegate(ref: R, prop: KProperty<*>): ReadOnlyProperty<R, T> = delegate() @Suppress("UNCHECKED_CAST") private fun <R> delegate(): ReadOnlyProperty<R, T> = object : ReadOnlyProperty<R, T> { override fun getValue(thisRef: R, property: KProperty<*>): T { val hash = clazz.hashCode() val cached = singletonsCache[hash] if (cached != null && cached.javaClass == clazz) return cached as T return initBlock().apply { singletonsCache[hash] = this } } } } private val singletonsCache = HashMap<Int, Any>() fun <T> clearSingleton(clazz: Class<T>) : Boolean { val hash = clazz.hashCode() val result = singletonsCache[hash] if (result?.javaClass != clazz) return false singletonsCache.remove(hash) return true } inline fun <reified T : Any> singletonLazy(noinline block: () -> T): SingletonLazy<T> = SingletonLazy(block, T::class.java) 

用法:

 val cat: Cat by singletonLazy { Cat() } fun main(args: Array<String>) { cat println(clearSingleton(Cat::class.java)) cat // cat will be created one more time println(singletonsCache.size) } class Cat { init { println("creating cat") } } 

当然,你可能有你自己的缓存策略。