Skip to content
Nate Ebel edited this page Jul 20, 2022 · 9 revisions

🖥 Lab 10: MVVM with Android Jetpack

Use Android Jetpack apis to implement an MVVM UI architecture in our app.

 

📝 Objectives

  1. In the studyguide package, create a new class StudyGuideViewModel

  2. Make StudyGuideViewModel extend ViewModel

    1. The ViewModel class will help us retain state across orientation changes and act as a layer of separation between our UI and Data application layers
  3. Create a property named title of type MutableStateFlow<String> and initialize it with a value of "Study Guide"

    1. val title: MutableStateFlow<String> = MutableStateFlow("Study Guide")
    2. This property exposes an observable stream of data that we will then use to update our UI anytime the value changes
    3. This moves us further in the direction of an MVVM UI architecture
  4. Within StudyGuideFragment create a property viewModel and initialize it using val viewModel: StudyGuideViewModel by viewModels()

    1. The call to by viewModels() is a delegate function coming from Android Jetpack
    2. This delegate will ensure we get the same Fragment instance back across Fragment recreation
    3. This is important for retaining state across configuration change
  5. Open fragment_study_guide.xml and provide an id named titleTextView for the TextView so we can update its value from StudyGuideFragment

  6. Override onViewCreated() within StudyGuideFragment

    1. onViewCreated() will be called after onCreateView()
    2. This can be a good place to do things like setup state collection of a ViewModel
  7. Within onViewCreated(), launch a new coroutine using lifecycleScope.launch{}.

    1. This will provide us with a coroutine which can be used to asynchronously collect changes in our title StateFlow
    2. Coroutines can be thought of as "lightweight threads". They are Kotlin's primary primitive for performing non-blocking operations.
    3. By launching our coroutine within lifecycleScope, it will ensure that our state collection is only active for as long as the Fragment
  8. Inside the call to launch{}, call repeateOnLifecycle(Lifecycle.State.STARTED) {}

    1. Within this call, we can setup the collection of our UI state to ensure we only respond to UI changes while the Fragment is active on screen
    2. repeatOnLifecycle() will cancel and re-launch as the lifecycle moves in and out of the target state.
    3. This helps ensure we are not trying to update the UI while the app is in the background
  9. Inside repeatOnLifecycle{} call collect{} on viewModel.title and update binding.titleTextView with the new title value

  10. Open StudyGuideViewModel and add an init{} block so we can run some code when our ViewModel is instantiated

  11. Within init{} use viewModelScope.launch{} to create a new coroutine.

  12. Make a call to delay(3000) to simulate an async operation by suspending the coroutine for 3 seconds

    1. The delay() function, is a suspending function coming from the coroutines library. It suspends the coroutine for the specified period of time. It's similar to Thread.sleep(). However, delay() does not block the entire Thread; only the coroutine.
  13. After the delay() call, update the value of the title StateFlow to Study Guide Fragment using title.update { "Study Guide Fragment" }

  14. Re-deploy the app and notice how the title TextView's value changes automatically after the 3 second delay

  15. Create a new data package in your root project directory

  16. Create a Note data class with the following properties

    1. title: String
    2. category: String
    3. content: String
  17. In StudyGuideViewModel, create a data class UiState with the following properties

    1. title: String
    2. notes: List<Note>
  18. Remove the existing title StateFlow property, and replace it with a single property named state of type MutableStateFlow<UiState>

    1. Update the initial value to provide the initial title and an empty set of Notes. (We will display notes in the next labs.)
    2. Refactor the updating of the title within init to state.update { currentValue -> currentValue.copy(title = "Study Guide Fragment") }
    3. Update the Flow collection within StudyGuideFragment to bind the title from the UiState

 

✨ Challenges

  1. Update MyNotesFragment to use a ViewModel with a UiState that controls the displayed title TextView
  2. Update NoteDetailFragment to use a ViewModel with a UiState that controls the displayed title, category, and content
  3. Update CreateNoteFragment to use a ViewModel with a UiState that controls the categories displayed in the Spinner dropdown

 

🖥 Lab 10 Hints: MVVM with Android Jetpack

💡Useful Resources

  1. Android Jetpack ViewModel Overview
  2. Using ViewModel to shared data between Fragments
  3. Using StateFlow in Android development
  4. StateFlow and SharedFlow
Clone this wiki locally