Android ViewModels: Should dataclasses expose livedata properties? - android

Given this scenario:
Model
data class User(var id: int, var name: String)
View Model
val Users: LiveData<List<User>>
val SelectedUser: LiveData<User>
fun changeSelectedUserName(){SelectedUser.Name = "foo"}
UI
<android:TextView Text="#{viewmodel.SelectedUser.name}"/>
<android:Button Text="Change!" onClik="#{() -> viewmodel.changeSelectedUserName()}"/>
When user clicks 'Change!' button the textview won't change because the 'name' field is not LiveData.
Questions
Should data class re-expose its fields as LiveData too?
If so, what will happen to regular fields? Are they replaced or keeped with another naming convention?
What is the correct naming convention if I'm using retrofit? So I can keep both the interface methods and LiveData working with the less amount of code?

Your issue is that you are modifying the User object properties directly, rather than update the LiveData.
For this to work, you have to do one of the following:
Make User extend BaseObservable, and invoke notifyPropertyChanged(BR.name) when the name property changes, and remove the LiveData<User>.
Make User extend BaseObservable, and put #Bindable annotation on the property getters, and remove LiveData<User>.
Make User properties val, and to make a modification, create a new User instance with the changed properties, and set it as value of the MutableLiveData<User>.
Ditch SelectedUser entirely, and replace it with two ObservableFields, one for selectedId: ObservableInt, and one for selectedName: ObservableField<String>. Now you can modify the values in place and also create bindings against it from databinding.
Remove databinding and use viewbinding instead, now you don't have to worry about notifying the databinding framework of property changes. 😏
Should data class re-expose its fields as LiveData too?
No

Related

Kotlin backing property in Android ViewModel

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.

Is it proper to use ViewModel for the ListView and the <T> in the ListView?

Preamble
In trying to get my head around the Kotlin classes to implement Android's ViewModel (and MVVM pattern) as used with Fragments and Activities, it is not clear to me of the trade-offs among the various complex classes especially how they have inherited implicit operations and visible methods (e.g., from the observer objects, managed scope, etc.) versus the old O-O approach of passing list-items and lists between activities in an intent as a bundle or reference, etc.
To illustrate my learning dilemma, I am implementing a crunchy cookie and and a jar to contain the cookies. The cookies can be created, consumed and viewed inside the cookie jar.
Android code tends to be vague on details of classes and the tutorials use deprecated versions, so it is difficult to follow best-practices with the latest version of the Android Architecture Component libraries.
Pseudo Kotlin code:
data class CrunchieCookie : {
var flavor: String?
var calories: String?
var photo: ImageView?
}
class CrunchieCookieViewModel : ViewModel() {
val _crunchieCookie: CrunchieCookie?
val crunchieCookie: CrunchieCookie = _crunchieCookie
}
class CookieJarListViewModel: ViewModel() {
val _cookieJar: MutableLiveData<CrunchieCookie>?
val cookieJar: LiveData<CrunchieCookie> = _cookieJar
}
Purpose
I am expecting to create, update and destroy crunchie-cookies
I am expecting to put crunchie-cookies in a cookie-jar (and take them out)
I am expecting to list all the crunchie-cookies in the cookie-jar in a scrolling ListView
I am expecting to click on a crunchie-cooking in the cookie-jar to open an detail view of the cookie
Finally, storing the cookie-jar in a remote DB, so planning for the local/remote data-source in the future
So, to my way of thinking, the cookie viewmodel will be used in CRUD operations and reused in the detail view from the list model.
MAKING #Tenfour04 's COMMENT AN ANSWER.
Your ViewModel should have a LiveData<List>. The Fragment containing the ListView should observe the LiveData for changes and pass the List along to the ListView when the LiveData value changes. If you're actually just modifying the contents of a MutableList, then you need to set the value of the MutableLiveData to that same list to inform it that there's a change it needs to notify observers about. – Tenfour04 Sep 9 at 0:02

Why does LiveData better than MutableLiveData?

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.

Android MVVM Livedata best practice

I am experiencing the new architectural components from google namely LiveData and ViewModel. By combining both APIs we can have the view model listening and updating the data in a reactive way.
My question is how data should be represented in a ViewModel more specifically, which way is better between having data exploded as separate fields as the following
class UserViewMode : ViewModel() {
var name = MutableLiveData<String>
vat lastName = MutableLiveData<String>
}
Or by encapsulating the data in a data holder/model class which contains both name and last name and having the view model observing this model class in a LiveData observer as the following
class UserViewMode : ViewModel() {
var user = MutableLiveData<User>
}
Thanks in advance.
Second approach is better.
class UserViewModel : ViewModel() {
var user = MutableLiveData<User>
}
Because encapsulating data inside a model (User) object is better than keeping all the data separate.
Main advantages I can see are
1. Clean code and architecture.
2. Model object can be used/passed between other components like GSON (to parse data into model object), Room database.
If there are multiple User objects and they need to be presented in a RecyclerView then you have to encapsulate the data into one object. Otherwise the code becomes a mess with multiple lists.
I think it depends only on how you get the data and you should think of are the fields changing separately or not?
For ex, if you are getting it like:
User, than there is no need to separate it into fields
On the other hand if you are changing the name separately from lastName you should have two fields for that.
Do it how it makes sense.

ViewModel backing properties [kotlin]

Looking to the code of some Google's demo app (like sunflower or Google io 2018 app) and I've noticed that for the viemodels' backing properties they use a separate instance of the same type with a custom getter; like this:
private val _userData: MutableLiveData<User>
val userData: LiveData<User>
get() = _userData
but why do they do that? Isn't better to directly make the _userData accessible?
Could it be because while _userData is a MutableLiveData they don't want the observer to be able to change the value?
userData which is exposed to the Activity or Fragment must be immutable since the view only needs to observe to the LiveData. So, we need to make the actual _userData returns a LiveData.
One way is using the Kotlin coding convention and create two variables, _userData and userData, one is mutable and another one is not:
If a class has two properties which are conceptually the same but one
is part of a public API and another is an implementation detail, use
an underscore as the prefix for the name of the private property.

Categories

Resources