0
0
Android Kotlinmobile~20 mins

SavedStateHandle in Android Kotlin - Mini App: Build & Ship

Choose your learning style9 modes available
Build: Counter Screen with SavedStateHandle
A simple counter screen that saves its count value using SavedStateHandle so the count persists across process death and configuration changes.
Target UI
---------------------
| Counter Screen    |
|-------------------|
| Count: 0          |
|                   |
| [+] Increment     |
|                   |
---------------------
Display a count starting at 0
Add a button labeled '+' to increment the count
Use SavedStateHandle in ViewModel to save and restore the count
Count value should persist after screen rotation or app process death
Starter Code
Android Kotlin
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView

class CounterViewModel(private val state: SavedStateHandle) : ViewModel() {
    // TODO: Add count property using SavedStateHandle
    // TODO: Add increment function
}

class MainActivity : AppCompatActivity() {
    private lateinit var viewModel: CounterViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // TODO: Initialize ViewModel with SavedStateHandle

        val countText = findViewById<TextView>(R.id.countText)
        val incrementButton = findViewById<Button>(R.id.incrementButton)

        // TODO: Observe count and update UI

        incrementButton.setOnClickListener {
            // TODO: Call increment on ViewModel
        }
    }
}
Task 1
Task 2
Task 3
Task 4
Task 5
Solution
Android Kotlin
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer

class CounterViewModel(private val state: SavedStateHandle) : ViewModel() {
    companion object {
        private const val COUNT_KEY = "count"
    }

    private val _count = MutableLiveData(state.get<Int>(COUNT_KEY) ?: 0)
    val count: LiveData<Int> = _count

    fun increment() {
        val newCount = (_count.value ?: 0) + 1
        _count.value = newCount
        state.set(COUNT_KEY, newCount)
    }
}

class MainActivity : AppCompatActivity() {
    private lateinit var viewModel: CounterViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        viewModel = ViewModelProvider(this, object : ViewModelProvider.Factory {
            override fun <T : ViewModel> create(modelClass: Class<T>): T {
                if (modelClass.isAssignableFrom(CounterViewModel::class.java)) {
                    @Suppress("UNCHECKED_CAST")
                    return CounterViewModel(SavedStateHandle()) as T
                }
                throw IllegalArgumentException("Unknown ViewModel class")
            }
        }).get(CounterViewModel::class.java)

        val countText = findViewById<TextView>(R.id.countText)
        val incrementButton = findViewById<Button>(R.id.incrementButton)

        viewModel.count.observe(this, Observer { count ->
            countText.text = "Count: $count"
        })

        incrementButton.setOnClickListener {
            viewModel.increment()
        }
    }
}

We created a CounterViewModel that takes a SavedStateHandle to store the count value. The count is stored in a MutableLiveData initialized from the saved state or 0 if none exists. The increment() function updates the count and saves it back to SavedStateHandle.

In MainActivity, we initialize the ViewModel with a factory that provides a SavedStateHandle. We observe the count LiveData to update the UI text. When the '+' button is clicked, we call increment() to increase the count.

This setup ensures the count value survives configuration changes and process death because SavedStateHandle saves the state automatically.

Final Result
Completed Screen
---------------------
| Counter Screen    |
|-------------------|
| Count: 3          |
|                   |
| [+] Increment     |
|                   |
---------------------
User taps '+' button increments count by 1
Count text updates immediately to show new count
Count value persists after rotating the device
Count value persists if app is killed and restored by system
Stretch Goal
Add a 'Reset' button that sets the count back to zero and updates the saved state.
💡 Hint
Add a new function reset() in ViewModel that sets count to 0 and updates SavedStateHandle. Add a button in layout and call reset() on click.