Manipulating LiveData data in the ViewModel

Transformations.map takes the input of one LiveData, applies a transformation (a function), and outputs another LiveData.

class MyViewModel : ViewModel() {

    companion object {
        private const val DONE = 0L
        private const val ONE_SECOND = 1000L
        private const val COUNTDOWN_TIME = 6000L
    }

    // Timer value
    private val _currentTime = MutableLiveData<Long>()
    val currentTime: LiveData<Long>
        get() = _currentTime

    val currentTimeString = Transformations.map(currentTime,{time -> // This takes in the current timer value and applies a time format before outputting it. Because it is a MutableLiveData it can be observed in a layout xml via data binding
        DateUtils.formatElapsedTime(time)
    })

    private val timer: CountDownTimer

    init {
        timer = object : CountDownTimer(COUNTDOWN_TIME, ONE_SECOND) {
            override fun onTick(millisUntilFinished: Long) {
                _currentTime.value = millisUntilFinished/ ONE_SECOND
            }

            override fun onFinish() {
                _currentTime.value = DONE
                _eventGameFinish.value = true
            }
        }
        timer.start()
    }
}

 

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <variable
            name="myViewModel"
            type="com.example.android.myapp.MyViewModel" />
    </data>

        <TextView
            android:id="@+id/timer_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{myViewModel.currentTimeString}" /> // Call the LiveData from the ViewModel

</layout>

For more complex operations you may need to use a SwitchMap or MediatorLiveData. Allows manipulation and combination of more than one LiveData.