Intro to Android Development
  • Welcome
  • Syllabus
  • Hack Challenge
  • Resources
    • Lecture Videos
    • Ed Discussion
    • Git & GitHub Help/How-To
    • Setting up Android Studio
    • Starting an Android Studio Project & Making an Emulator
    • Importing, Exporting, & Submitting Your Projects to CMS
  • SP25 Course Material
    • Week 1 | Course Logistics, Kotlin, & Basic UI
      • Relevant Links
      • Demo/Lecture: Eatery Card
      • A0: Eatery Card (Follow-Along)
    • Week 2 | States, Components, LazyColumn
      • Relevant Links
      • Demo: Todo List
      • A2: Shopping List
    • Week 3 | Navigation & Animations
      • Relevant Links
      • Demo: Onboarding
      • A3: Stock Trading (RobbingGood)
    • Week 4 | MVVM and Flows
      • Relevant Links
      • Demo: Eatery Card 2
      • A4: Chat of a Lifetime
    • Week 5 | Dumb Components & UIEvents
      • Relevant Links
      • Demo: Music Player
      • A5: Rate My Vibe
    • Week 6 | Coroutines, Networking, JSON
      • Relevant Links
      • Demo: Retrofit
      • A6: You Should Even Lift, Bro.
  • Bonus Week | Android Job Search
    • Relevant Links
    • Android Technical Interview Question!
  • Textbook
    • 1. Introduction to the Editor and Views
      • 1.1 Introduction to the Editor
      • 1.2 SDK Management
      • 1.3 Kotlin Overview
      • 1.4 Views
      • 1.5 Android Studio Project Demo + Understanding The Editor
    • 2. Jetpack Compose
      • 2.1 Introduction
      • 2.2 Layouts
      • 2.3 Modifiers
      • 2.4 Animations
      • 2.5 Lazy Lists
      • 2.6 Reactive UI
    • 3. Intents and Manifest
      • 3.1 Activities
      • 3.2 Implicit Intents
      • 3.3 Explicit Intents
      • 3.4 Manifest
      • 3.5 Permissions
      • 3.6 Summary
    • 4. Navigation
      • 4.1 Types of Navigation
      • 4.2 Implementation of the Bottom Navigation Bar
    • 5. Data and Persistent Storage
      • 5.1 Singleton Classes
      • 5.2 Shared Preferences
      • 5.3 Rooms
      • 5.4 Entities
      • 5.5 Data Access Objects
      • 5.6 Databases
    • 5.5 Concurrency
      • 5.5.1 Coroutines
      • 5.5.2 Implementation of Coroutines
      • 5.5.3 Coroutines with Networking Calls
    • 6. Networking and 3rd Party libraries
      • 6.1 HTTP Overview
      • 6.2 3rd Party Libraries
      • 6.3 JSON and Moshi
      • 6.4 Retrofit
      • 6.5 Summary
    • 7. MVVM Design Pattern
      • 7.1 Key Idea
      • 7.2 Implementation Ideas
    • 8. Flows
    • 9. The Art and Ontology of Software
    • 10. 🔥 Firebase
      • 10.1 Setting up Firebase
      • 10.2 Authentication
      • 10.3 Analytics
      • 10.4 Messaging
      • 10.5 Firestore
  • Additional Topics
    • Git and GitHub
    • Exporting to APK
  • Archive
    • Archived Native Android Textbook Pages
      • 1. Layouts and More Views
        • 1.1 File Structure and File Types
        • 1.2 Resource Files
        • 1.3 Button and Input Control
        • 1.4 ViewGroups
        • 1.5 Summary + A Note On Chapter 2 Topics
      • 2. RecyclerViews
        • 2.1 RecyclerViews
        • 2.2 RecyclerView Performance
        • 2.3 Implementation of a Recycler View
        • 2.4 Implementation with Input Controls
        • 2.5 Filtering RecyclerViews
        • 2.6 Recyclerview Demo
      • 3. ListViews and Searching
        • 3.1 ListView vs. RecyclerView
        • 3.2 ListView Performance
        • 3.3 Implementation of a ListView
        • 3.4 Searching in a List View
      • 4. Fragments
        • 4.1 What are Fragments?
        • 4.2 Lifecycle of a Fragment
        • 4.3 Integrating a Fragment into an Activity
        • 4.4 Sharing Data Between Fragments
        • 4.5 Fragment Slide Shows
      • 5. OkHttp
      • 6. Activity Lifecycle
      • 7. Implementation of Tab Layout
    • Fall 2024 Course Material
      • Lecture 1 & Exercise 1: Introduction to Android
      • Lecture 1.5: Beauty of Kotlin
      • Lecture 2 & HW 2: Modifiers, Lazylists and Reactive UI
      • Lecture 3 & HW 3: Animations, Intents and Manifest
      • Lecture 4 & HW 4: Coroutines & Navigation
      • Lecture 5 & HW 5: Persistent Storage, Networking, and JSON Parsing
      • Lecture 6 & HW 6: MVVM, Flows
      • Bonus Lectures & Bonus HW
      • Bonus Lecture: Industry Practice
    • Spring 2024 Course Material
      • Lecture 1 & Exercise 1: Introduction to Android
      • Lecture 4 & HW 4: LazyLists
      • Lecture 6 & HW 6: Networking, Data, and Persistent Storage
    • Spring 2020 Course Material
      • Week 1: Intro to the Editor
      • Week 2: Views and Layouts
      • Week 3: Intent and Manifest
      • Week 4: ListView and RecyclerView
      • Week 5: Fragments
      • Week 6: Networking
    • Spring 2021 Lecture & HW 8: Networking & 3rd Party APIs
    • HackOurCampus Workshop
Powered by GitBook
On this page
  • View
  • ViewModel
  • Model
  • The value of the Model abstraction
  • Events
  • Unidirectional data flow

Was this helpful?

  1. Textbook
  2. 7. MVVM Design Pattern

7.1 Key Idea

MVVM stands for model-view-viewmodel, let's go over each of these and see how they provide a framework for state management.

Previous7. MVVM Design PatternNext7.2 Implementation Ideas

Last updated 9 months ago

Was this helpful?

View

The view is what you are already most familiar with, it consists of the composables that the user sees as they explore the app. Here's an example of a CommentView composable:

@Composable
fun CommentView(
    username: String,
    commentText: String
) {
    Column(modifier = Modifier.padding(8.dp)) {
        Text(
            text = username,
            fontWeight = FontWeight.Bold,
            fontSize = 16.sp,
            modifier = Modifier.padding(bottom = 4.dp)
        )
        BasicText(text = commentText)
    }
}

ViewModel

The main purpose of a ViewModel from a coding standpoint store the state of a screen such that it survives configuration changes, such as the user rotating their screen or changing their screen size (like splitting to multiple windows with a folding phone). But from an organization standpoint, the ViewModel takes a larger role than just the state holder. The ViewModel is also responsible for storing the "business logic", or intermediary logic that we use to process data between the View and the Model. A common example of business logic is password validation. If we want to make sure a password is secure enough before sending it off to the Model to create the user's account, this validation logic should be stored in the ViewModel.

So to reiterate, a ViewModel has two main functions:

  1. Retrieve data from the Model, and nicely package it into a digestible state for the View

  2. Process / validate user input from the view and send it to the Model.

Having our code separate in this way makes testing and maintenance far easier. If you need to change the business logic, then you shouldn't need to touch the UI at all. If you want to change how the UI looks, you shouldn't need to change any business logic to accommodate that. This also allows for easier testing. We can test our business logic in a completely separate environment from our UI.

The ViewModel can send notifications to the UI, also referred to as effects. For example, if the UI requests the ViewModel to validate a credit card number and the validation fails, the ViewModel can trigger an effect to show a snackbar indicating the number is invalid.

Model

The model acts as a bridge between the ViewModel and the actual database that we use. The model abstracts away common data operations that the ViewModel might use. This way, if the database changes in the future, we only have to change these abstractions without needing to change the business logic.

The value of the Model abstraction

Here's an example of how a model could be valuable: let's say that we have a fitness app and we want to show the user a monthly summary of their workout statistics. At this fitness app company, the backend team doesn't have the bandwidth to create a custom summary endpoint just for your use case, so they expect you to assemble the data from other endpoints.

You create two functions in your model: getMonthlySteps and getMonthlyCalories. You use these in your ViewModel to nicely package the data into a summary data class for your View, and all is well.

Later down the road, the backend team decides it's too costly for you to make two API calls to generate one summary item, so they decide to give you a custom summary endpoint that contains both of these data points. Then because of your great architectural decisions, all you have to do is change the implementation of getMonthlySteps and getMonthlyCalories. The method spec can stay the same, so their use in the ViewModel can stay the same too. To reimplement this to only make one API call, you might cache the resulting summary item from getMonthlySteps and have getMonthlyCalories read from the cache, or vice versa.

Events

Just as your ViewModel can send notifications to your View, you may want your Model to send notifications to your ViewModel. For example, if the Model abstracts away a long-running database operation from the ViewModel, and this operation fails, we may want to notify the ViewModel that this is the case. With this notification, the ViewModel could update the state of the View, or even send an effect to the View alerting it.

Unidirectional data flow

You may have noticed a pattern throughout this chapter: state flows down, and events flow up.

The Model holds the actual data that the view needs for its state, this data flows down to the ViewModel. The ViewModel aggregates and packages this data into a nice readable form for the View, and then sends this state down to the view.

The view sends events to the ViewModel, for example the user pressing a button. The ViewModel then processes this event and sends it to the Model, which then processes the event and sends it to the database.

Notice that CommentView contains only logic for displaying the username and commentText. This is an important detail that generalizes to the concept of views as a whole: views should not store any business logic. Ideally, the view's only responsibility should be to properly display a state. In this case, the state of CommentView is the username text and commentText. So then where should the business logic go? Read on to discover

This is a nice pattern to be aware of, since being mindful of it when creating an app provides benefits that help with scalability and testability. The idea even extends beyond Android development, as you'll see it used in other frontend frameworks. I highly recommend reading the section on from the Android documentation. It explains the concept much better than I can and provides great guidance on how to follow the principle.

🤩
unidirectional data flow
Keep this visual in mind while reading!