Android LiveData

We use LiveData to observe data inside ViewModel from an Activity or Fragment. If any change or update to this data happens, we can automatically update the Activity or Fragment.

LiveData only updates observers in an active lifecycle state. Its benefits are to automatically update the UI when app data changes.

LiveData vs MutableLiveData

Data inside LiveData is read-only. It cannot be updated as it has no public method to modify it. MutableLiveData can be updated.

Implementation

Add the following into your App’s gradle.build

dependencies {
	def lifecycle_version = "2.1.0"
	implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
}

We have the following ViewModel.

class MainActivityViewModel(startingTotal: Int): ViewModel {
	
	var total = MutableLiveData<Int>()
	
	init {
		total.value = startingTotal
	}
	
	fun setTotal(input: Int) { total.value = input }
	
}

How we use it from another Activity.

override fun onCreate(savedInstanceState: Bundle?) {
	super.onCreate(savedInstanceState)
	
	viewModel = ...
	viewModel.total.observe(this, Observer {
		// this will be executed when MutableLiveData changes. 
		binding.resultTextView.text = it.toString()
	})
	
	button.setOnClickListener { viewModel.setTotal(5) }
}

How to encapsulate LiveData

We want to encapsulate total, as leaving it public is no good design.

  1. We mark it as private.
  2. We need to declare a new public variable. As we’re not going to edit it, it should be LiveData. We can use Kotlin backing property to return LiveData from a getter function.
class MainActivityViewModel(startingTotal: Int): ViewModel {
	private var total = MutableLiveData<Int>()
	val totalData: LiveData<Int>
	get() = total
	
	init {
		total.value = startingTotal
	}
	
	fun setTotal(input: Int) { total.value = input }
	
}

Now we may change the onCreate() method.

override fun onCreate(savedInstanceState: Bundle?) {
	super.onCreate(savedInstanceState)
	
	viewModel = ...
	viewModel.totalData.observe(this, Observer {
		// this will be executed when MutableLiveData changes. 
		binding.resultTextView.text = it.toString()
	})
	
	button.setOnClickListener { viewModel.setTotal(5) }
}