fresh digitable

めんどくさかったなってことを振り返ったり振り返らなかったりするための記録

WeakReferenceに包みつつNonNullなプロパティとしてアクセスするためのデリゲートプロパティ

例えばこういうのを

private val _foo= WeakReference<FooActivity>(activity)
private val foo: FooActivity get() = requireNotNull(_foo.get())

こんな感じで

private val foo: FooActivity by weakRef(activity)

使えるようにしたい。そんなときはデリゲートプロパティを使って、次のようなものを用意するとよい。

fun <T : Any> weakRef(t: T): ReadOnlyProperty<Any, T> = WeakRefProperty(t)

private class WeakRefProperty<T : Any>(t: T) : ReadOnlyProperty<Any, T> {
    private val _t: WeakReference<T> = WeakReference(t)

    override fun getValue(thisRef: Any, property: KProperty<*>): T = requireNotNull(_t.get())
}

上の例で、activityじゃなくてそれが持っているViewにアクセスしたいというようなときは、lazyと組み合わせて、

fun <T : Any, R : Any> weakRef(
    t: T,
    lazyBlock: (T) -> R
): ReadOnlyProperty<Any, R> = WeakRefPropertyWithLazy(t, lazyBlock)

private class WeakRefPropertyWithLazy<R : Any, T : Any>(
    r: R,
    lazyBlock: (R) -> T
) : ReadOnlyProperty<Any, T> {
    val rRef: R by weakRef(r)
    val tRef: WeakReference<T> by lazy { WeakReference(lazyBlock(rRef)) }

    override fun getValue(thisRef: Any, property: KProperty<*>): T = requireNotNull(tRef.get())
}

こんな感じのものを用意してやると

private val bar: View by weakRef(activity) { it.findViewById<VIew>(R.id.view_bar) }

このように書ける。NavControllerとかを取得するのもよい。

UdonRoad2/WeakRefProperty.kt at master · akihito104/UdonRoad2 · GitHub