ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Follow publication

Exploring ViewModel Internals

Jaewoong Eum
ProAndroidDev
Published in
5 min readJan 1, 2025

Unsplash@tbzr

At Google I/O 2017, Google introduced Architecture Components, a collection of libraries designed to address core challenges in Android development and provide guidance for app architecture. These components, part of the broader Android Jetpack library suite, include tools like Jetpack ViewModel to simplify state management and lifecycle awareness.

Jetpack ViewModel has long been a popular topic of discussion among developers, often serving as a cornerstone for implementing MV* design patterns, such as MVVM or MVI. It is frequently compared to Microsoft’s original MVVM pattern, highlighting its versatility and adaptation for Android app architecture.

Some developers might prefer implementing ViewModels manually, but Jetpack ViewModel remains a great role in many common scenarios due to its seamless integration with various libraries. It works effectively with Hilt for dependency injection into ViewModel constructors, with Jetpack Navigation for scoping ViewModel lifecycles, and with Jetpack Compose for exposing screen UI states to composable functions, making it a cornerstone of modern Android app architecture.

In this article, you’ll explore ViewModel's inner workings, diving into its internal implementation and understanding how it operates under the hood featured in Dove Letter. Dove Letter is a subscription repository where you can learn, discuss, and share new insights about Android and Kotlin with industrial Android developer interview questions, tips with code, articles, discussion, and trending news. If you’re interested in joining, be sure to check out “Learn Kotlin and Android With Dove Letter.”

ViewModel and ViewModelImpl

Let’s start by examining the ViewModel class. ViewModel is an abstract class that serves as a base for other classes, offering several key functions to manage UI-related data in a lifecycle-conscious way. Its internal implementation (JVM, Android) is outlined in the following code:

You might have noticed that the ViewModel class contains a property of type ViewModelImpl, and most of its functions simply delegate their calls to the corresponding functions in ViewModelImpl. To fully understand how these functions operate, we should examine the internal workings of the ViewModelImpl class:

Let’s break it down one by one. The ViewModelImpl class contains the following key properties and functions:

  • isCleared: This property holds the state indicating whether the ViewModel has already been cleared. Many function calls depend on this property, as it governs whether certain operations are permissible.
  • closeables and keyToCloseables: These properties manage AutoCloseable instances. closeables is a set, while keyToCloseables is a map, allowing for efficient storage and retrieval of closeable resources.
  • addCloseable(): There are two variations of this function, but their primary purpose is the same — to add an AutoCloseable instance to either the map or set. This is done in a thread-safe manner using a SynchronizedObject, ensuring proper coordination in multi-threaded environments.
  • clear(): This function is responsible for closing all stored AutoCloseable instances from both closeables and keyToCloseables. It also resets the closeables set, ensuring no lingering resources are left behind.

AutoCloseable

Now you might be wondering about the exact purpose of AutoCloseable. Originating from Java, AutoCloseable is a functional interface designed to handle resource management. In Kotlin, AutoCloseable works similarly and allows you to create an instance that executes a specified closeAction when its close() function is called as you’ve seen in the code below:

By now, you should have a clearer understanding of AutoCloseable and its role in resource management. Essentially, the ViewModel maintains a map and a set of AutoCloseable instances, which can be added directly to the ViewModel using the addCloseable() function. When the ViewModel is cleared, all stored AutoCloseable instances are systematically closed by invoking their close() function, ensuring proper cleanup of resources.

So what can you achieve with AutoCloseable? While its use cases may not be extensive, it is particularly useful for delegating tasks that must be executed in the ViewModel's onCleared() function. For instance, when working with RxJava or RxKotlin, you need to call dispose() on a CompositeDisposable to clean up all Disposable objects when the ViewModel is cleared.

By utilizing AutoCloseable, you can create a custom class or function to manage CompositeDisposable, ensuring that all disposables are automatically disposed of when the ViewModel is cleared. This approach simplifies resource cleanup and integrates seamlessly with the ViewModel lifecycle.

Ensure that you are using version 2.8.5 or later of the Jetpack Lifecycle library.

At first glance, this approach might seem like over-engineering, as it adds more code compared to manually disposing of the CompositeDisposable. However, consider a scenario where you have 100+ ViewModel classes—this method not only simplifies resource management but also eliminates the risk of forgetting to call the dispose() function in the onCleared() method, ensuring consistent and reliable cleanup across your codebase.

viewModelScope

One of the most common examples of leveraging AutoCloseable is the viewModelScope, which is frequently used in daily development to launch coroutine scopes within a ViewModel. Let’s take a look at the internal implementation of viewModelScope:

Examining the internal implementation of viewModelScope, it first checks if a ViewModel scope has already been created; if it exists, it retrieves the existing scope. If not, it creates a new ViewModelScope using the createViewModelScope() function. To fully understand this process, it's essential to delve into what the createViewModelScope() function does.

The createViewModelScope() function returns a coroutine scope called CloseableCoroutineScope, which implements AutoCloseable. This scope ensures that the coroutine context is canceled when the close() function is called.

Internally, the mechanism works as follows: viewModelScope creates a custom coroutine scope that is automatically canceled by leveraging the AutoCloseable interface. This scope is then registered with the ViewModel by adding it through the addCloseable() function, ensuring seamless integration with the ViewModel lifecycle.

Conclusion

In this article, you’ve explored the internal mechanisms of Jetpack ViewModel, gaining a deeper understanding of how it operates, particularly the implementation and functionality of viewModelScope. While the complete ViewModel mechanism is more intricate—encompassing dedicated providers and lifecycle scoping tailored to Android components—the insights shared here should be sufficient for most project requirements. Hopefully, this article has clarified the workings of ViewModel and provided valuable insights into the internal behavior of viewModelScope.

This topic initially has been covered in Dove Letter, a private repository offering daily insights on Android and Kotlin, including topics like Compose, architecture, industry interview questions, and practical code tips. In just 20 weeks since its launch, Dove Letter has surpassed 400 individual subscribers and 12business/lifetime subscribers. If you’re eager to deepen your knowledge of Android, Kotlin, and Compose, be sure to check out ‘Learn Kotlin and Android With Dove Letter’.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Published in ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Written by Jaewoong Eum

Senior Developer Advocate @ RevenueCat 🥑 • GDE for Android • OSS engineer. Love psychology, magic tricks, and writing poems. https://github.com/skydoves

No responses yet

Write a response