kotterknife
kotterknife copied to clipboard
Reset cached bindings
Fixes #5 by keeping a registry of cached lazies and resetting them on purpose.
Seems this patch causes memory leaks so it shouldn't be merged. I'll try to find a better solution.
The memory leak is fixed now. @JakeWharton, can you merge these commits please?
Anybody alive here?
without this change fragments cannot be used when the views are destroyed (e..g with page views )
I support this. I would like to see this merged too.
@Suppress("UNCHECKED_CAST")
private fun <T : Any, V : View> required(id: Int, finder: T.(Int) -> View?)
= Lazy { t: T, desc -> t.finder(id) as V? ?: viewNotFound(id, desc) }
@Suppress("UNCHECKED_CAST")
private fun <T : Any, V : View> optional(id: Int, finder: T.(Int) -> View?)
= Lazy { t: T, desc -> t.finder(id) as V? }
@Suppress("UNCHECKED_CAST")
private fun <T : Any, V : View> required(ids: IntArray, finder: T.(Int) -> View?)
= Lazy { t: T, desc -> ids.map { t.finder(it) as V? ?: viewNotFound(it, desc) } }
@Suppress("UNCHECKED_CAST")
private fun <T : Any, V : View> optional(ids: IntArray, finder: T.(Int) -> View?)
= Lazy { t: T, desc -> ids.map { t.finder(it) as V? }.filterNotNull() }
// Like Kotlin's lazy delegate but the initializer gets the target and metadata passed to it
private class Lazy<T : Any, V>(private val initializer: (T, KProperty<*>) -> V) : ReadOnlyProperty<T, V> {
private object EMPTY
private var value: Any? = EMPTY
override fun getValue(thisRef: T, property: KProperty<*>): V {
if (value == EMPTY) {
value = initializer(thisRef, property)
LazyRegistry.register(thisRef, this)
}
@Suppress("UNCHECKED_CAST")
return value as V
}
internal fun reset() {
value = EMPTY
}
}
private object LazyRegistry {
private val lazyMap = WeakHashMap<Any, MutableCollection<Lazy<*, *>>>()
fun register(target: Any, lazy: Lazy<*, *>) {
lazyMap.getOrPut(target, { Collections.newSetFromMap(WeakHashMap()) }).add(lazy)
}
fun reset(target: Any) {
lazyMap.get(target)?.forEach { it.reset() }
}
}
object ButterKnife {
fun reset(target: Any) {
LazyRegistry.reset(target)
}
}
We need this functionality to correctly implement Fragments being detached and re-attached (ex: ViewPager).