I'm trying Jetpack Navigation component
and have set up a very basic navigation graph with just 2 Fragments with one home fragment (Foo
) containing a button which calls a navigation action to open the other fragment (Bar
).
With only the basic Android usage and functions it works as intended, I can navigate back to Foo
by pressing the back button and navigate forward to Bar
again.
I implemented this convenience delegate
class for binding views by id in my preferred way (Im originally an iOS dev).
class FindViewById<in R, T: View>(private val id: Int) {
private var view: T? = null
operator fun getValue(thisRef: R, property: KProperty<*>): T {
var view = this.view
if (view == null) {
view = when (thisRef) {
is Activity -> thisRef.findViewById(id)!!
is Fragment -> thisRef.requireView().findViewById(id)!!
is View -> thisRef.findViewById(id)!!
else -> throw NullPointerException()
}
this.view = view // Comment out to never cache reference
}
return view
}
}
This allows me to write code like this
class FragmentFoo: Fragment() {
private val textView: TextView by FindViewById(R.id.text_view)
private val button: Button by FindViewById(R.id.button)
...
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
button.setOnClickListener {
findNavController().navigate(R.id.action_foo_to_bar)
}
}
}
Now all of a sudden when I navigate to Bar
and then press the back button I arrive at Foo
again but I cannot navigate forward to Bar
. If I remove the line this.view = view
in FindViewById
it works again.
My guess is there is some memory related issue, though I tried wrapping the view
inside a WeakReference
but it didn't solve the problem.
I think it is a good idea performance-wise to cache the found view in the delegate.
Any idea why this is occurring and how I can resolve the problem while caching the found view?
Edit
My intention is not to find another way of referencing views but rather why this delegate implementation disrupts the Navigation component so I don't experience it again if I were to make another custom delegate in the future.
Solution
is Fragment -> {
thisRef.viewLifecycleOwnerLiveData.value!!.lifecycle.addObserver(object: LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
if (event == Lifecycle.Event.ON_STOP) this@FindViewById.view = null
}
})
return thisRef.requireView().findViewById(id)!!
}
from Kotlin delegate disrupting Navigation
No comments:
Post a Comment