Bird
Raised Fist0
Android Kotlinmobile~20 mins

ViewModel creation in Android Kotlin - Mini App: Build & Ship

Choose your learning style10 modes available
Build: Counter Screen
A simple screen that shows a number and a button to increase it using ViewModel to keep the count.
Target UI
-------------------
|   Counter App   |
|                 |
|      0          |
|                 |
|  [Increase +]   |
-------------------
Create a ViewModel class to hold the counter value
Display the current count in the UI
Add a button that increases the count when clicked
Use ViewModel to keep the count even if the screen rotates
Starter Code
Android Kotlin
import androidx.activity.ComponentActivity
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModelProvider
import android.widget.Button
import android.widget.TextView

class MainActivity : ComponentActivity() {
    private val counterViewModel: CounterViewModel by viewModels()

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

        val countTextView = findViewById<TextView>(R.id.countTextView)
        val increaseButton = findViewById<Button>(R.id.increaseButton)

        // TODO: Observe the count LiveData from ViewModel and update countTextView

        // TODO: Set onClickListener on increaseButton to increase count in ViewModel
    }
}

// TODO: Create CounterViewModel class here
Task 1
Task 2
Task 3
Solution
Android Kotlin
import androidx.activity.ComponentActivity
import androidx.activity.viewModels
import android.os.Bundle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.LiveData
import android.widget.Button
import android.widget.TextView

class MainActivity : ComponentActivity() {
    private val counterViewModel: CounterViewModel by viewModels()

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

        val countTextView = findViewById<TextView>(R.id.countTextView)
        val increaseButton = findViewById<Button>(R.id.increaseButton)

        counterViewModel.count.observe(this) { count ->
            countTextView.text = count.toString()
        }

        increaseButton.setOnClickListener {
            counterViewModel.increaseCount()
        }
    }
}

class CounterViewModel : ViewModel() {
    private val _count = MutableLiveData(0)
    val count: LiveData<Int> = _count

    fun increaseCount() {
        _count.value = (_count.value ?: 0) + 1
    }
}

We created a CounterViewModel class that holds a MutableLiveData integer starting at 0. This LiveData keeps the count value.

In MainActivity, we get the ViewModel instance using by viewModels(). We observe the count LiveData and update the TextView whenever the count changes.

The button's click listener calls increaseCount() on the ViewModel, which increments the count. Because the count is in ViewModel, it survives screen rotations and keeps the number consistent.

Final Result
Completed Screen
-------------------
|   Counter App   |
|                 |
|      3          |
|                 |
|  [Increase +]   |
-------------------
When user taps 'Increase +' button, the number in the center increases by 1
The count stays the same if the device is rotated
Stretch Goal
Add a Reset button that sets the count back to zero
💡 Hint
Add another button in the layout and a resetCount() method in ViewModel to set _count.value = 0

Practice

(1/5)
1. What is the main purpose of a ViewModel in Android development?
easy
A. To define the layout of the app screen
B. To handle user input events directly
C. To store and manage UI-related data in a lifecycle conscious way
D. To manage network requests

Solution

  1. Step 1: Understand ViewModel role

    A ViewModel is designed to hold UI data safely during configuration changes like screen rotations.
  2. Step 2: Compare options

    Only To store and manage UI-related data in a lifecycle conscious way describes this purpose correctly; others describe unrelated tasks.
  3. Final Answer:

    To store and manage UI-related data in a lifecycle conscious way -> Option C
  4. Quick Check:

    ViewModel purpose = store UI data safely [OK]
Hint: ViewModel holds UI data safely during screen changes [OK]
Common Mistakes:
  • Confusing ViewModel with UI layout classes
  • Thinking ViewModel handles user input directly
  • Assuming ViewModel manages network calls
2. Which of the following is the correct way to declare a ViewModel class in Kotlin?
easy
A. class MyViewModel extends ViewModel {}
B. class MyViewModel : ViewModel() {}
C. fun MyViewModel() : ViewModel {}
D. val MyViewModel = ViewModel()

Solution

  1. Step 1: Recall Kotlin class syntax

    Kotlin uses a colon (:) to extend a class and parentheses for constructor calls.
  2. Step 2: Check each option

    class MyViewModel : ViewModel() {} uses correct Kotlin syntax for extending ViewModel; others use Java syntax or invalid declarations.
  3. Final Answer:

    class MyViewModel : ViewModel() {} -> Option B
  4. Quick Check:

    Kotlin inheritance uses ':' and parentheses [OK]
Hint: Use ':' to extend class in Kotlin, not 'extends' [OK]
Common Mistakes:
  • Using Java syntax 'extends' in Kotlin
  • Declaring ViewModel as a function
  • Assigning ViewModel to a val without class
3. Given this ViewModel code snippet, what will be the output when counter.value is printed after increment() is called twice?
class CounterViewModel : ViewModel() {
  val counter = MutableLiveData(0)
  fun increment() {
    counter.value = (counter.value ?: 0) + 1
  }
}
medium
A. 2
B. 1
C. null
D. 0

Solution

  1. Step 1: Understand initial value and increment

    counter starts at 0; each increment adds 1 to current value.
  2. Step 2: Calculate after two increments

    After first call: 0 + 1 = 1; after second call: 1 + 1 = 2.
  3. Final Answer:

    2 -> Option A
  4. Quick Check:

    Two increments from 0 = 2 [OK]
Hint: Each increment adds 1; two calls add 2 total [OK]
Common Mistakes:
  • Forgetting to unwrap nullable value
  • Assuming counter resets each time
  • Confusing LiveData with normal variable
4. Identify the error in this ViewModel code:
class SampleViewModel : ViewModel() {
  val data = MutableLiveData<String>()

  fun updateData(newData: String) {
    data.value = newData
  }

  fun getData(): String {
    return data.value
  }
}
medium
A. ViewModel class must be abstract
B. MutableLiveData cannot hold String values
C. updateData() should not modify LiveData value
D. getData() returns nullable String but declared as non-nullable

Solution

  1. Step 1: Check LiveData type and usage

    MutableLiveData<String> can hold String values; updateData() correctly sets value.
  2. Step 2: Analyze getData() return type

    data.value is nullable String?, but getData() returns non-nullable String, causing a type mismatch.
  3. Final Answer:

    getData() returns nullable String but declared as non-nullable -> Option D
  4. Quick Check:

    LiveData value is nullable; return type must match [OK]
Hint: LiveData.value is nullable; match return types carefully [OK]
Common Mistakes:
  • Ignoring nullable type of LiveData.value
  • Thinking ViewModel must be abstract
  • Believing LiveData can't hold String
5. You want to create a ViewModel that holds a list of user names and updates the UI reactively. Which is the best way to declare and update this list inside your ViewModel?
hard
A. class UserViewModel : ViewModel() {\n val users = MutableLiveData(emptyList())\n fun addUser(name: String) {\n users.value = users.value?.plus(name)\n }\n}
B. class UserViewModel : ViewModel() {\n val users = mutableListOf<String>()\n fun addUser(name: String) {\n users.add(name)\n }\n}
C. class UserViewModel : ViewModel() {\n var users = listOf<String>()\n fun addUser(name: String) {\n users += name\n }\n}
D. class UserViewModel : ViewModel() {\n val users = LiveData()\n fun addUser(name: String) {\n users.value = listOf(name)\n }\n}

Solution

  1. Step 1: Identify reactive data holder

    MutableLiveData<List<String>> allows UI to observe changes and update reactively.
  2. Step 2: Check update method correctness

    class UserViewModel : ViewModel() {\n val users = MutableLiveData<List<String>>(emptyList())\n fun addUser(name: String) {\n users.value = users.value?.plus(name)\n }\n} uses users.value?.plus(name) to add a user immutably and update LiveData, which is correct.
  3. Step 3: Review other options

    class UserViewModel : ViewModel() {\n val users = mutableListOf<String>()\n fun addUser(name: String) {\n users.add(name)\n }\n} uses mutableList but not LiveData, so UI won't update reactively. class UserViewModel : ViewModel() {\n var users = listOf<String>()\n fun addUser(name: String) {\n users += name\n }\n} uses var list but no LiveData. class UserViewModel : ViewModel() {\n val users = LiveData<List<String>>()\n fun addUser(name: String) {\n users.value = listOf(name)\n }\n} tries to instantiate LiveData directly, which is abstract and invalid.
  4. Final Answer:

    class UserViewModel : ViewModel() {\n val users = MutableLiveData<List<String>>(emptyList())\n fun addUser(name: String) {\n users.value = users.value?.plus(name)\n }\n} -> Option A
  5. Quick Check:

    Use MutableLiveData with immutable updates for reactive UI [OK]
Hint: Use MutableLiveData and update list immutably for UI updates [OK]
Common Mistakes:
  • Using mutableList without LiveData for UI data
  • Trying to instantiate LiveData directly
  • Modifying list without updating LiveData value
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard