'Is passing LiveData to ViewModel constructor valid?
I'm building an app using MVVM with Room where a list of data is displayed in an activity. The list is obtained from the Room database in a LiveData object and observed in the activity.
Upon wanting to add another item to the list, a DialogFragment is shown which prompts the user to pick a value from a list of possible values, however, if the chosen value is already present in the database, it will not allow the user to press the dialog positive button.
I have implemented separate ViewModels for the Activity and DialogFragment. Both viewmodels make separate calls to access the data from the database, even though they will always be looking at the same data. This to me seems kind of reduntant, so I'm wondering, what would be the best way to make the two viewmodels share the same data, with only one call to fetch it from the database made.
One idea I got is to add a parameter for a LiveData in the DialogFragment constructor, and then when creating the DialogFragment viewmodel, I would pass the reference for the LiveData containing the list, obtained from the activity viewmodel.
class AddItemDialogVewModel(items: LiveData<List<Item>>) :
ViewModel() {
//check if item to be added already exists in items
}
create a Factory class for the ViewModel and then in the DialogFragment:
val dialogViewModel = ViewModelProvider(this, new AddItemViewModelFactory(activityViewModel.items))
.get(AddItemDialogViewModel.class);
Does anyone see any issues with this and is there a better way to do this. I never saw it done before so I'm unsure if it's good practice.
Thanks
Solution 1:[1]
If the activity and fragment show the same data from a table in the database, the value that the user have chosen will always be present in the database.
What is it that you want to achieve here?
By the way if that's what you really want to do you don't need to implement the ViewModel for the dialog fragment. You can use a shared ViewModel from the parent activity.
Your approach of using a shared LiveData is correct. But passing it in a constructor is not the correct way to do it.
I'm going to use Kotlin Property Delegates for ViewModels. Add these dependencies:
implementation "androidx.fragment:fragment-ktx:1.4.1"
implementation "androidx.activity:activity-ktx:1.4.0"
Activity ViewModel
class ItemsActivityViewModel : ViewModel() {
private val _items = MutableLiveData<List<Item>>()
val items: LiveData<List<Item>> get() = _items
.
.
.
// Get data from Room Database ...
}
Activity
class ItemsActivity : AppCompatActivity() {
private val viewModel by viewModels<ItemsActivityViewModel>() // Can only be use with an empty constructor ViewModel
override fun onCreate(savedInstanceState:Bundle) {
super.onCreate(savedInstanceState)
viewModel.items.observe(this) { items ->
// Do something
}
}
}
Fragment
class AddItemDialogFragment : DialogFragment() {
private val activityViewModel by activityViewModels<ItemsActivityViewModel>()
override fun onViewCreated(view:View, savedInstanceState:Bundle) {
activityViewModel.items.observe(viewLifecycleOwner) { items ->
// Do something
}
}
}
Or you can create your ViewModel from ViewModelProvider.
Activity
class ItemsActivity : AppCompatActivity() {
lateinit var viewModel: ItemsActivityViewModel
override fun onCreate(savedInstanceState:Bundle) {
super.onCreate(savedInstanceState)
viewModel = ... // Create your ViewModel
viewModel.items.observe(this) { items ->
// Do something
}
}
}
Fragment
class AddItemDialogFragment : DialogFragment() {
private lateinit var activityViewModel: ItemsActivityViewModel
override fun onCreate(savedInstanceState:Bundle) {
super.onCreate(savedInstanceState)
activityViewModel = (requireActivity() as ItemsActivity).viewModel
}
override fun onViewCreated(view:View, savedInstanceState:Bundle) {
activityViewModel.items.observe(viewLifecycleOwner) { items ->
// Do something
}
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Sovathna Hong |
