Kotlin惰性属性和值重置:可重置的惰性委托 [英] Kotlin lazy properties and values reset: a resettable lazy delegate
问题描述
所以我在Android上使用kotlin
,并且在放大视图时,我倾向于执行以下操作:
So I use kotlin
for android, and when inflating views, I tend to do the following:
private val recyclerView by lazy { find<RecyclerView>(R.id.recyclerView) }
此方法将起作用.但是,在某些情况下,它将使应用程序出错.如果这是一个片段,并且该片段进入了堆栈,则将再次调用onCreateView
,并将重新创建该片段的视图层次结构.这意味着,延迟启动的recyclerView将指出一个不再存在的旧视图.
This method will work. However, there is a case in which it will bug the app. If this is a fragment, and the fragment goes to the backstack, onCreateView
will be called again, and the view hierarchy of the fragment will recreated. Which means, the lazy initiated recyclerView will point out to an old view no longer existent.
解决方案是这样的:
private lateinit var recyclerView: RecyclerView
并初始化onCreateView
中的所有属性.
And initialise all the properties inside onCreateView
.
我的问题是,有什么办法可以重置惰性属性,以便可以再次对其进行初始化?我喜欢所有的初始化工作都是在类的顶部完成的,这有助于使代码井井有条.在以下问题中发现了特定的问题:之后的kotlin android片段为空的回收器视图后退
My question is, is there any way to reset lazy properties so they can be initialised again? I like the fact initialisations are all done at the top of a class, helps to keep the code organised. The specific problem is found in this question: kotlin android fragment empty recycler view after back
推荐答案
这里是可重置懒惰的快速版本,它可能更优雅,并且需要仔细检查线程安全性,但这基本上是个主意.您需要管理(保持跟踪)懒惰的委托人,以便可以调用reset,然后可以管理和重置.这会将lazy()
包装在这些管理类中.
Here is a quick version of a resettable lazy, it could be more elegant and needs double checked for thread safety, but this is basically the idea. You need something to manage (keep track) of the lazy delegates so you can call for reset, and then things that can be managed and reset. This wraps lazy()
in these management classes.
这是您的最后一堂课的样子,例如:
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 = s.x
val y1 = s.y
val z1 = s.z
assertEquals(x1, s.x)
assertEquals(y1, s.y)
assertEquals(z1, s.z)
s.seed++ // without reset nothing should change
assertTrue(x1 === s.x)
assertTrue(y1 === s.y)
assertTrue(z1 === s.z)
s.lazyMgr.reset()
s.seed++ // because of reset the values should change
val x2 = s.x
val y2 = s.y
val z2 = s.z
assertEquals(x2, s.x)
assertEquals(y2, s.y)
assertEquals(z2, s.z)
assertNotEquals(x1, x2)
assertNotEquals(y1, y2)
assertNotEquals(z1, z2)
s.seed++ // but without reset, nothing should change
assertTrue(x2 === s.x)
assertTrue(y2 === s.y)
assertTrue(z2 === s.z)
}
}
这篇关于Kotlin惰性属性和值重置:可重置的惰性委托的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!