I have a custom class Card. I use it to create an array using arrayOfNulls() like this:
var cards: Array<Array<Card?>?> = Array(n) { arrayOfNulls<Card?>(n) }
where n is an Int(Kotlin).
Now I need to move this variable in my ViewModel class and wrap it around a LiveData class (preferably MutableLiveData).
How should I declare & initialize the cards variable in my AndroidViewModel class?
Create a MutableLiveData-variable, that wraps your cards and add it as class variable inside your ViewModel:
val mutableLiveData = MutableLiveData<Array<Array<Card?>?>>()
You can now access and subscribe to this variable from your Fragment/Activity/...
To change the value of the mutableLiveData-Variable just change the value:
mutableLiveData .value = cards
and all subscribers of this LiveData-Variable will get the new value.
Related
I am new in Kotlin and confused in underscore in a variable as _view.
Please help me.
class MainActivityPresenter(_view: View): Presenter {
private var view: View = _view
Maybe you can read about Names for backing properties and you'll understand it better.
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
This is common in viewModel where you have your private val of a MutableLiveData and then you have the same name variable without the underscore that is the one is accessible from outside but not mutable.
Example :
private val _user: MutableLiveData<User>
val user: LiveData<User>
get() = _user
In your case would be to don't confuse the View that is in your Presenter and the View that is by constructor.
I have a ViewModel class that looks like this:
class EditUserViewModel(
private val initUser: User,
) : ViewModel() {
private val _user = MutableLiveData(initUser)
val user: LiveData<User>
get() = _user
fun hasUserChanged() = initUser != _user.value
}
User can update some properties of the User data class instance through the UI.
To check if there are any changes when navigating from the fragment I use hasUserChanged method.
The problem is that is always false. I checked and it seems that the initialUser changes every time I change the _user MutableLiveData.
Why is that? Is the initial value of MutableLiveData passed by reference? I always thought that Kotlin is a "pass-by-value" type of language.
Update:
The problem seems to disappear when copying initUser before putting it inside the MutableLiveData.
private val _user = MutableLiveData(initUser.copy())
But it still doesn't make sense to me why I have to do that.
Kotlin is like java and they are pass-by-value. If you implement the equals function in User class, or make it as data class (which implements the equals function implicitly), it makes you sure that the content of the user objects is checked by != operator.
Update
If you are changing the value of LiveData directly, for example like this:
_user.value.name = "some name"
it means that you are changing the name property of the initUser, because _user.value exactly refers to the object that the initUser does. Consequently, the != operator always returns false, because we have one object with two references to it.
Now, when you are doing so:
private val _user = MutableLiveData(initUser.copy())
you are creating a deep copy of initUser (let's call it X) which is a new object in memory with the same property values of initUser.
Thus, by changing its properties like: _user.value.name = "some name", in fact, you are making this change on X, not initUser. It leads to preserving the initial values in initUser, meaning do not changing them, and solving the issue.
I would like to create a unit test of this class but I would like the instance of the countryRepository: CountryRepository to be a mock in the case of the test.
I could create an alternative constructor to pass another instance but it doesn't seem like a great solution
How could I do?
class CountryListModel {
var countryRepository:CountryRepository = CountryRepositoryImp()
}
Pass it inside the constructor with default value:
class CountryListModel(val countryRepository:CountryRepository = CountryRepositoryImp())
I'm trying out databinding for a view that's supposed to display data exposed through a LiveData property in a viewmodel, but I've found no way to bind the object inside the LiveData to the view. From the XML I only have access to the value property of the LiveData instance, but not the object inside it. Am I missing something or isn't that possible?
My ViewModel:
class TaskViewModel #Inject
internal constructor(private val taskInteractor: taskInteractor)
: ViewModel(), TaskContract.ViewModel {
override val selected = MutableLiveData<Task>()
val task: LiveData<Task> = Transformations.switchMap(
selected
) { item ->
taskInteractor
.getTaskLiveData(item.task.UID)
}
... left out for breivety ...
}
I'm trying to bind the values of the task object inside my view, but when trying to set the values of my task inside my view I can only do android:text="#={viewmodel.task.value}". I have no access to the fields of my task object. What's the trick to extract the values of your object inside a LiveData object?
My task class:
#Entity(tableName = "tasks")
data class Task(val id: String,
val title: String,
val description: String?,
created: Date,
updated: Date,
assigned: String?)
For LiveData to work with Android Data Binding, you have to set the LifecycleOwner for the binding
binding.setLifecycleOwner(this)
and use the LiveData as if it was an ObservableField
android:text="#{viewmodel.task}"
For this to work, Task needs to implement CharSequence. Using viewmodel.task.toString() might work as well. To implement a two-way-binding, you'd have to use MutableLiveData instead.
why are you using two way binding for TextView
android:text="#={viewmodel.task.value}"
instead use like this android:text="#{viewmodel.task.title}"
if I have a class
data class item(val address: String = ""
)
its declared in my viewmodel
var varLive: MutableLiveData = MutableLiveData()
and later on I post it from my viewmodel
varLive.postValue(scootersList[marker])
in my xml I have
<TextView
...
android:text="#{vModel.varLive.address}"
/>
And I can't access item.address and get a databinding error.
I can check if the varLive is null and tht is it
Do I really have to declare each of the livedata class fields as a live data? If I have a class holding 100 members?
for some stupid reason you have to specify a getter method in your viewmodel, so databinding can pick it up. like so:
fun getvarLive() = varLive
Kotlin actially does that for you. But databinding won't bind Kotlin getters. Seriosly annoying