Blog Infos
, , , ,

Inthe third part of this series of articles, we will continue discussing best practices for using Android ViewModels.

In the previous parts, we’ve discussed 🔄🔄🔄

  1. Avoid initializing the state in the init {} block. ✅ (read here)
  2. Avoid exposing mutable states.
  3. Use update{} when using MutableStateFlows:

Find the detailed information in the posts below:—–1833ce3ddd2b——————————–—–1833ce3ddd2b——————————–

Let’s look at the Key discussion points for this series and refresh our memories, In this part we’ll discuss #4 and #5 in the list below

Key Discussion Points for This Series
  1. Avoid initializing state in the init {} block. ✅ (read here)
  2. Avoid exposing mutable states. ✅
  3. Use update{} when using MutableStateFlows: ✅
  4. 👉 Try not to import Android dependencies in the ViewModels:
  5. 👉 Lazily inject dependencies in the constructor.
  6. Embrace more reactive and less imperative coding.
  7. Avoid initializing the ViewModel from the outside world.
  8. Avoid passing parameters from the outside world.
  9. Avoid hardcoding Coroutine Dispatchers.
  10. Unit test your ViewModels.
  11. Avoid exposing suspended functions.
  12. Leverage the onCleared() callback in ViewModels.
  13. Handle process death and configuration changes.
  14. Inject UseCases, which call Repositories, which in turn call DataSources.
  15. Only include domain objects in your ViewModels.
  16. Leverage shareIn() and stateIn() operators to avoid hitting the upstream multiple times.
Let’s get started!
#4-Try not to import Android dependencies in the ViewModels:

The guideline to avoid importing Android dependencies into ViewModels, with specific exceptions for classes like LiveData and its transformers, is rooted in the principles of clean architecture and testability. Here’s a breakdown of what this means and why it’s important:

1. Separation of Concerns
  • Android Dependencies like R (resources) and other Android framework classes are directly tied to the Android operating system and its context. These classes are responsible for managing UI elements, accessing Android resources (strings, drawable resources, etc.), and interacting with the Android system (intents, context, etc.).
  • By keeping Android dependencies out of ViewModels, you ensure a clear separation of concerns. The ViewModel does not need to know about the Android context or UI elements to do its job, which is managing data for the UI.
but what If I need to emit some sort of string from my viewmodels as part of my state?

for those cases using Kotlin’s sealed interface would be ideal, find more in the following article:—–1833ce3ddd2b——————————–

2. Testability
  • Android Dependencies can make unit testing more complex because they often require a running Android environment (like an emulator or a physical device). This can slow down tests and make them more brittle.
  • ViewModels without Android dependencies can be tested on the JVM without needing an Android environment, leading to faster and more reliable tests. LiveData and its transformers are exceptions because they are designed to be lifecycle-aware and can be easily mocked or observed in tests.
3. Portability

– Code that does not depend directly on the Android framework is more portable and easier to maintain. It can be reused in different parts of your application or even in other projects with minimal changes. and even in the future viewmodels can be swapped out to Slack’s Circuit Presenters easily to migrate your codebase to Kotlin Multi-Platform

But what about LiveData and Transformers?! 🤔
  • LiveData and its transformers (like and Transformations.switchMap) are designed to be used in ViewModels. They are lifecycle-aware, allowing ViewModels to update the UI in a safe way, responding to lifecycle events of the Activities and Fragments.
  • These classes do not tie your ViewModel to specific Android UI elements or resources. Instead, they provide a mechanism for the ViewModel to emit data changes in a lifecycle-aware manner, which the UI layer can observe.
# 5-Not injecting dependencies Lazily in constructors:

Injecting dependencies directly into ViewModel constructors without lazy initialization can lead to:

  1. increased startup times ⏱️
  2. higher memory usage 📈💾
  3. unnecessary CPU resource utilization 🚫🖥️

Lazy initialization defers the creation of dependencies until they’re actually needed, optimizing app performance and efficiency. This approach is particularly beneficial for large, rarely used, or conditionally needed dependencies. Balancing immediate and lazy initialization based on dependency use cases is crucial for optimal app performance.

Not using lazy initialization for dependencies in ViewModel constructors can impact your Android application’s performance and resource utilization, especially during startup or when creating instances of those ViewModels. Here’s how non-lazy injection compares to lazy injection and why the latter is often preferred in certain scenarios:

Job Offers

Job Offers

There are currently no vacancies.


, ,

Migrating to Jetpack Compose – an interop love story

Most of you are familiar with Jetpack Compose and its benefits. If you’re able to start anew and create a Compose-only app, you’re on the right track. But this talk might not be for you…
Watch Video

Migrating to Jetpack Compose - an interop love story

Simona Milanovic
Android DevRel Engineer for Jetpack Compose

Migrating to Jetpack Compose - an interop love story

Simona Milanovic
Android DevRel Engin ...

Migrating to Jetpack Compose - an interop love story

Simona Milanovic
Android DevRel Engineer f ...


When to Use Lazy Initialization
  • Large or Rarely Used Dependencies: If a ViewModel has large dependencies or ones that are infrequently accessed, lazy initialization is beneficial as it avoids the cost of initializing these resources until they’re actually needed.– Conditional Dependencies: For dependencies that are only needed under certain conditions (e.g., based on user actions or specific app states), lazy initialization prevents unnecessary setup.
#Case Study:
class BookViewModel @Inject constructor(
    @IoDispatcher private val ioDispatcher: CoroutineDispatcher,
    private val bookmarkUseCase: dagger.Lazy<BookmarkUsecase>,

Imagine having a bookmark action in your ViewModel that will get triggered if the user clicks on the bookmark button, for this dependency which gets injected through BookViewModel constructor we can leverage a Lazy injection which will postpone the creation of the Usecase until it is needed.

Great job on making it to the end of this article! 💪

  • Follow my YouTube channel for video tutorials and tips on Android development
  • ✨✨ If you need help with your Android ViewModels or a project, Book a 1:1 or a Pair-Programming meeting with me, Book a time now 🧑‍💻🧑‍💻🧑‍💻

If you like this series of articles smash the 👏clap button as many times! So this can continue with the follow-up articles!

This article is previously published on



Automation is a key point of Software Testing once it make possible to reproduce…
Every good Android application should be well tested to minimize the risk of error…
Using annotations in Kotlin has some nuances that are useful to know
One of the latest trends in UI design is blurring the background content behind the foreground elements. This creates a sense of depth, transparency, and focus,…

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.