I'm trying out StateFlow in DataBindings and in all examples I can find, most look like a copy of this one, two variables are used in the ViewModel for one data binding. One private MutableStateFlow and a public StateFlow. And the StateFlow is pretty much just reading the value from the MutableStateFlow. Why is this? Wouldn't it be easier to just have one variable, a MutableStateFlow and skip the StateFlow variable all together?
This is just a simple case of encapsulation (and is unrelated to data binding/Android). From a technical standpoint, this is a redundant step and doesn't make a difference. From a design standpoint however, it restricts modification of the StateFlow value outside of your containing class.
This is quite a common pattern with 'observable data holders' (MutableLiveData and LiveData), which can be thought as similar to having a property with a private setter. In fact, if you only need to collect the flow and not access its value, you could even use Flow as the exposed type (although as #MarkKeen pointed out, this won't work with data binding).
Related
as I mentioned in the title, I'm curious about the general differences between the two. Can you help with this? I couldn't find the specific differences as there are complex examples on the internet.
What are the differences in terms of performance?
In which scenarios does it provide advantages?
Using StateFlow with Kotlin Flow is advantageous. But what is the risk of not switching to StateFlow in a project using LiveData?
Is Google deprecating LiveData? :)
I just switched to StateFlow, so this is a great time for me to answer your question.
What are the differences in terms of performance?
Honestly, I don't know, but since it's pushed by Kotlin and Android, just trust them :).
In which scenarios does it provide advantages?
For LiveData you are not forced to give an initial value, it may end up writing more code in init{}; But for StateFlow you are Forced to give an initial value (including null), it may save your code a bit.
For LiveData even if you give an initial value, you still need to do Null Check when you access its value (see this), it's kind of annoying. But that's not gonna happen on StateFlow - it will be what it should be.
For LiveData you cannot easily, or elegantly observe data changes JUST inside ViewModel, you are gona use observeForever() which is also mentioned in here. But for StateFlow it's easy, do it like following:
class FirstViewModel() : ViewModel() {
val uiScope = viewModelScope
val name = MutableStateFlow("Sam") //must have initial value
//val name = MutableStateFlow<String?>(null) //null is acceptable
init {
observeName()
}
private fun observeName() = uiScope.launch { //must run in coroutine scope
name.collect { name -> //for Fragment / Activity, use lifecycleScope.launch{}
//do your stuff
}
}
}
Using StateFlow with Kotlin Flow is advantageous. But what is the risk of not switching to StateFlow in a project using LiveData?
What is the risk of not switching to Kotlin in a project using Java? :)
Is Google deprecating LiveData?
I would say yes, and they would say no, no for "not yet to say it loudly" :).
Was just wondering, why is it better to use backing property for MutableLiveData, instead of just exposing getter function that returns the MutableLiveData property as live data. For example:
Why this code
private val _registeredDevicesObservable: MediatorLiveData<List<Data>> = MediatorLiveData()
val registeredDevicesObservable: LiveData<List<Data>> = _registeredDevicesObservable
is better or more acceptable than this one
private val _registeredDevicesObservable: MediatorLiveData<List<Data>> = MediatorLiveData()
fun registeredDevicesObservable(): LiveData<List<Data>> = _registeredDevicesObservable
As also when this getter function is keeping the LiveData immutability and keeps me from having that little annoying underscore syntax when accessing the property inside the view model.
It's just less idiomatic in the language to use a function that simply returns an already-available object. You're free to do it any way you like, but if others have to work with your code, it will be easier to understand and work with if you follow general conventions.
There isn't as strong a convention about whether the backing property should have a leading underscore in the name, so if you don't like it, don't use it.
One reason to stick with these conventions is there is a proposed upcoming language feature to allow you to do this without a backing property, and so if you're following the conventions, it will be very easy to update your code to eliminate the backing property.
I have one Activity and i have created one View-model for it. I have created different classes like
UiUtil( show, hide view, hide key board ), Network layer , Data Base layer, AppUtil( for common functionality like Collection check, String validation, Date Conversion etc)
My question is, In MVVM design pattern is Activity can use these utility classes directly or it needs to use these classes via View-model, if it via view model then in the view-model i have to write a method that just call utility classes method . like below TimeDateManager is utility class used in view-model
class HomeViewModel: BaseViewModel()
{
fun prepareTimeAmPmToDisplay(context: Context, alarm: Alarm): String
{
return TimeDateManager.prepareTimeAmPmToDisplay(context, alarm)
}
}
Architectures are not obligatory, they are recommendational, thus you can change their usage in quite wide range. The only stopper should be a common sense(if it is present of course).
In this particular case the usage of utility class inside an Activity maybe ok, based on your ViewModel construction and its way of communication with View(read Activity).
For example if you have some LiveData that sends some kind of event(for ex. data loaded from backend or alarm trigger) inside your ViewModel and your View listens to it, I think it is ok to use util classes inside an Observer in Activity. Especially if this utils method doesn't depend on any ViewModel or Repository data. The direct utils usage in Activity is not limited by this usecase, though - there are plenty of others.
I understand that this may be an unpopular opinion in modern time of "clean approach" but I believe that this "clean approach" sometimes complicates stuff where it shouldn't, thus if mixing things a bit does not brake overall architecture but rather makes some thing more readable and easy to maintain - I would go for it.
Hope it helps.
My approach toward MVVM is simple, ViewModel is responsible for business logic, dealing with repositories (Network, Database, etc.) and all of the non-UI codes preparing the required data for UI, just like the documentation:
A ViewModel object provides the data for a specific UI component, such as a fragment or activity, and contains data-handling business logic to communicate with the model. For example, the ViewModel can call other components to load the data, and it can forward user requests to modify the data. The ViewModel doesn't know about UI components, so it isn't affected by configuration changes, such as recreating an activity when rotating the device.
On the other hand, ViewModels should not store a context (ApplicationContext is exceptional) and it's preferred that they do not use android APIs at all, so they become more testable (especially in the case on pure unit tests).
Also we are recommended to make use of LiveData in ViewModels and the UI has to observe the LiveData. For example, in onCreate of your Activity, you will call loadMainContent() method from VM, it calls getMainContent(page=1) from repository, and the repository will decide to load data from DB or network, and the result will be set on a LiveData were the View is listening for changes.
TL;DR
Sometimes it's even better to call these utilities from View rather than the VM. I'm pretty sure about your UiUtil also I think TimeDateManager is more view related rather than logic related. In addition, Network and DB layers are more efficient if called through a repository (which is responsible for caching, etc.) and VM can use that repo.
In many samples i see that:
class DataViewModel{
val data:LivaData<Int>
get() = _data
private val _data = MutableLiveData<Int>()
}
But more simply looks like this:
class DataViewModel{
val data = MutableLiveData<Int>()
}
so, why need this more complicated code construction with 2 fields?
It's a practice designed to restrict modification of the value from outside the class.
LiveData is read-only.
MutableLiveData, as the name implies, allows one to change the value it holds.
If you expose a MutableLiveData directly, like in your second example, any code which can access that data field could also modify the value it holds.
Exposing the ability to change data's content from outside DataViewModel class could make it harder to debug and reason about where data's content is coming from at any given time.
MutableLiveData is essentially a LiveData with public access to two methods setValue() and postValue() for modifying that data.
Therefore, MutableLiveData is needed if you plan to modify the values of the LiveData.
However, in programming, it's a common concept to make your variables immutable or restrict the access of those who can modify the data of an object. You wouldn't want to expose the ability to modify the contents of variables within an object if there's no need to do so.
Therefore, for MutableLiveData, we normally use a getter to get it's parent form, which is LiveData.
By getting only LiveData, we can ensure that those who access the LiveData object can only read the values stored within with no ability to change them.
In a sense, it's just the concept of why you should use private variables with getters.
Most of the MVVM examples are dealing with very simple user interfaces.
But lets say I have an activity with many views to update (i.e. lots of data)
As I read in other places, multiple ViewModel objects is a bad pattern.
So, as I see it there are two solutions for that:
Create a single object (and single LiveData for it), that wraps all other data objects.
But there's a problem with this - each data object that gets updated will cause the whole UI to update.
Create multiple objects (and multiple LiveData objects for it).
It means that I need to observe each LiveData object. Is there a problem with this pattern?
Thanks in Advance!
First Point you mentioned : Yes this is not optimal Pattern to do but if you have small data then, separating LiveDatas is more work for less gains
Second Point you mentioned : Yes this is more optimal, you can have a LiveData object for each View you want to update and observe them all from your activity or fragment. There are no issues in this Pattern.
About Mutilple ViewModels :
Multiple ViewModels Pattern in same Activty/Fragment is also an option if you have too many things(LiveData objects or funcitions) happening in one ViewModel. This is only recommended to make viewModels lighter. So only use this if you are having a large viewModel class
Create ViewModels for discrete types of information.
You could for example have a UserViewModel that deals with all state regarding a User. This means you can use the same ViewModel in another context, without pulling data that might not be necessary (as you would if you had a single God ViewModel).
Create as many LiveData objects as you need to model your view.
It is better to condense the data into logical objects, where possible. If only to keep things manageable.
If you have a User, you should use that for your LiveData instead of having a LiveData for E-mail address, Display name, Age, etc. That will make things much simpler for your data bindings. Try to keep things logically grouped together.