Richard
Richard

Reputation: 7433

Observe mutable live data of a data class's property changes

In Android Kotlin Fundamentals, the code mentions of using a backing property to encapsulate the MutableLiveData in ViewModel so that only the ViewModel itself can change said mutable value. Different from the practice, I'm using a data class instead. I would like to observe the changes to the property of the data class and display it in the UI.

Here's what I have so far.

class CourseViewModel : ViewModel() {
    private var _lastAccessedCourse: MutableLiveData<Course>
    val lastAccessedCourse: LiveData<Course>
        get() = _lastAccessedCourse
    // Some other code...

    fun updateProgress() {
        if (_lastAccessedCourse.value != null)
            _lastAccessedCourse.value = _lastAccessedCourse.value!!.let {
                it.progress += 5
                it
            }
    }

Then, I will observe the lastAccessedCourse in my UI like below. A button click updates the variable progress and that change is what I am observing.

binding.fragHomeLaReadButton.setOnClickListener {
    courseViewModel.updateProgress()
}

courseViewModel.lastAccessedCourse.observe(viewLifecycleOwner, Observer {
    binding.fragHomeLaProgress.progress = it.progress
})

My data class is simple.

data class Course(
    var name: String,
    var category: String,
    var progress: Int
)

This works. However, I have a concern. When I tried to updateProgress() without setting _lastAccessedCourse variable (and instead just adding 5 to progress), it seems like the change isn't observed. I suspect that this is because it doesn't observe the data class's property changes. Is this correct?

As can be seen, I'm returning a new Course to _lastAccessedCourse variable every time I call updateProgress(). Does this have a performance drawback? Is there a better practice to achieve what I want?

Upvotes: 1

Views: 4488

Answers (1)

Francesc
Francesc

Reputation: 29260

A MutableLiveData only notifies its observers if the value is changed. Changes to the class (Course in your case) are not observed.

For best practice, consider using an immutable data class for Course and assigning a new one to the LiveData each time:

data class Course(
    val name: String,
    val category: String,
    val progress: Int
)

val course = /* TODO: get current course */
val newCourse = course.copy(progress = course.progress + 5)
_lastAccessedCourse.value = newCourse

Upvotes: 3

Related Questions