android - Kotlin 惰性属性和值重置 : a resettable lazy delegate

标签 android properties kotlin lazy-initialization

所以我使用 kotlin for android,并且在膨胀 View 时,我倾向于执行以下操作:

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

这种方法会奏效。但是,在某些情况下,它会导致应用程序出错。如果这是一个fragment,并且fragment进入backstack,onCreateView会被再次调用,并且fragment的 View 层次将被重新创建。这意味着,惰性启动的 recyclerView 将指出一个不再存在的旧 View 。

解决办法是这样的:

private lateinit var recyclerView: RecyclerView

并初始化onCreateView里面的所有属性。

我的问题是,有没有办法重置惰性属性,以便它们可以再次初始化?我喜欢初始化都在类的顶部完成的事实,这有助于保持代码的组织性。具体问题在这个问题中找到:kotlin android fragment empty recycler view after back

最佳答案

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

以下是您的 final类的样子,例如:

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

resettablelazy的实现:

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)
   }
}

关于android - Kotlin 惰性属性和值重置 : a resettable lazy delegate,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35752575/

相关文章:

android - 我如何 adb 拉出 SD 卡中存在的文件夹的所有文件

PHP traits - 更改继承类中静态属性的值

Grails:理解 groovy DomainClass.properties

java - 网络安全配置 : Using Network Security Config from resource network_security_config debugBuild: true

inheritance - 抑制 Dokka 对 "No documentation for com.foo.Bar$toString()"的提示?

android - CSS 来显示响应式 Nag Bar?

java - Java中如何从字符串中提取url?

Android Volley HTTPS header 抛出 400

java - Properties.loadFromXML() 和 Properties.storeToXML() 方法的目的是什么?

android - Kotlin 相当于 Swift 的 defer 关键字