Setting up LiveData observer in custom view without LifecycleOwner
Solution 1
1 Option -
With good intention, you still have to do some manual work - like, calling onAttach
\ onDetach
Main purpose of Architecture components is to prevent doing this.
2 Option -
In my opinion is better, but I would say it's a bit wrong to bind your logic around ViewModel
and View
. I believe you can do same logic inside Activity/Fragment
without passing ViewModel and LifecycleOwner
to CustomView
. Single method updateData
is enough for this purpose.
So, in this particular case, I would say it's overuse of Architecture Components.
Solution 2
it doesn't make sense to manage the lifecycle of the the view manually by passing some reference of the activity to the views and calling onAttach/onDetach, when we already have the context provided when that view is created.
I have a fragment in a NavigationView that has other fragments in a view pager, more like a nested fragment hierarchy scenario.
I have some custom views in these top-level fragments, when the custom view is directly in the top fragment, I can get an observer like this
viewModel.itemLiveData.observe((context as ContextWrapper).baseContext as LifecycleOwner,
binding.item.text = "some text from view model"
}
when I have the custom view as a direct child of an activity I set it up directly as
viewModel.itemLiveData.observe(context as LifecycleOwner,
binding.item.text = "some text from view model"
}
in these activities, if I have a fragment and it has some custom view and I use the 2nd approach, I get a ClassCastException(), and I have to reuse these custom views in different places, both activities, and fragments (that's the idea of having a custom view)
so i wrote an extension function to set the LifeCycleOwner
fun Context.getLifecycleOwner(): LifecycleOwner {
return try {
this as LifecycleOwner
} catch (exception: ClassCastException) {
(this as ContextWrapper).baseContext as LifecycleOwner
}
}
now i simply set it everywhere as
viewModel.itemLiveData.observe(context.getLifecycleOwner(),
binding.item.text = "some text from view model"
}
Related videos on Youtube
kcrimi
Updated on June 04, 2022Comments
-
kcrimi about 2 years
I'm trying out the new Android Architecture components and have run into a road block when trying to use the MVVM model for a custom view.
Essentially I have created a custom view to encapsulate a common UI and it's respective logic to use throughout the app. I can set up the ViewModel in the custom view but then I'd have to either use
observeForever()
or manually set aLifecycleOwner
in the custom view like below but neither seem correct.Option 1) Using
observeForever()
Activity
class MyActivity : AppCompatActivity() { lateinit var myCustomView : CustomView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) myCustomView = findViewById(R.id.custom_view) myCustomView.onAttach() } override fun onStop() { myCustomView.onDetach() } }
Custom View
class (context: Context, attrs: AttributeSet) : RelativeLayout(context,attrs){ private val viewModel = CustomViewModel() fun onAttach() { viewModel.state.observeForever{ myObserver } } fun onDetach() { viewModel.state.removeObserver{ myObserver } } }
Option 2) Setting lifecycleOwner from Activity`
Activity
class MyActivity : AppCompatActivity() { lateinit var myCustomView : CustomView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) myCustomView = findViewById(R.id.custom_view) myCustomView.setLifeCycleOwner(this) } }
Custom View
class (context: Context, attrs: AttributeSet) : RelativeLayout(context,attrs){ private val viewModel = CustomViewModel() fun setLifecycleOwner(lifecycleOwner: LifecycleOwner) { viewModel.state.observe(lifecycleOwner) } }
Am I just misusing the patterns and components? I feel like there should be a cleaner way to compose complex views from multiple sub-views without tying them to the Activity/Fragment
-
Siamak almost 4 yearsWhy you don't use
observeForever(observer)
instead? It does not require a LifeCycleOwner and you can remove Observer inonDetachedFromWindow()
-
-
Bitcoin Cash - ADA enthusiast over 4 yearsFor people who like me use Custom Views instead of Fragments this is a problem. I will go with Option 1 as there is no way I am going back to Fragments and their LOL lifecycles.
-
user924 over 2 yearsa Fragment can have have two lifecycle owners: of fragment itself or of view of fragment (
viewLifecycleOwner
). In our case we need to getviewLifecycleOwner
somehow if custom view was inflated in fragment