Kotlin 延迟属性和值重置:可重置的延迟委托 [英] Kotlin lazy properties and values reset: a resettable lazy delegate
问题描述
所以我将 kotlin
用于 android,并且在膨胀视图时,我倾向于执行以下操作:
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) }
这个方法行得通.但是,在某些情况下,它会导致应用程序出错.如果这是一个fragment,并且这个fragment进入backstack,onCreateView
将被再次调用,并且fragment的视图层次结构将被重新创建.这意味着,惰性启动的 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 fragment empty recycler view after返回
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
推荐答案
这里是一个可重置懒惰的快速版本,它可以更优雅,需要仔细检查线程安全,但这基本上就是这个想法.您需要一些东西来管理(跟踪)懒惰的委托,以便您可以调用重置,然后可以管理和重置的东西.这将 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
resettable lazy 的实现:
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屋!