CHAPTER 22
Beginner
Clean Architecture and Repositories
Updated: May 16, 2026
30 min read
# CHAPTER 22
Clean Architecture and Repositories
1. Introduction
We have reached a critical architectural inflection point. In our current application, theViewModel is responsible for observing LiveData, launching Coroutines, executing Retrofit API calls, and interacting with the Room Database. This violates the Single Responsibility Principle. If the ViewModel decides *where* the data comes from (Network vs. Database), it becomes massively bloated and impossible to test. In professional Android development, we introduce an intermediary layer: the Repository. In this chapter, we will master Clean Architecture and the Repository Pattern. We will abstract data operations, enforce a Single Source of Truth, and orchestrate seamless synchronization between the remote cloud and local storage.
2. Learning Objectives
By the end of this chapter, you will be able to:- Understand the principles of the Repository Pattern in MVVM.
- Decouple data fetching logic from the UI Controller and ViewModel.
- Implement a Single Source of Truth caching strategy.
- Construct a Repository class that abstracts Room DAOs and Retrofit APIs.
- Pass Repository dependencies cleanly into the ViewModel.
3. The Problem: Bloated ViewModels
Imagine an app that shows a list of news articles.- The user opens the app.
- The ViewModel checks if the internet is connected.
- If yes, the ViewModel calls Retrofit to download articles.
- The ViewModel then saves the articles into Room.
- If no, the ViewModel queries Room to get cached articles.
4. The Solution: The Repository
The Repository is a plain Kotlin class. It sits between the ViewModel and your Data Sources (Retrofit & Room). The ViewModel asks the Repository: "Get me the articles." The ViewModel does not know, nor does it care, if the Repository gets them from the internet or the database. The Repository acts as the ultimate traffic controller.5. Single Source of Truth Strategy
The industry standard caching strategy works exactly like this:- 1. The ViewModel observes the Room Database via the Repository. (The database is the "Single Source of Truth").
- 2. Simultaneously, the Repository asks Retrofit for fresh data from the server.
- 3. Retrofit downloads the fresh data.
- 4. The Repository saves the fresh data directly into the Room Database.
-
5.
Because Room is being observed (returning
LiveData), the database updates instantly, which automatically pushes the fresh data up to the ViewModel and finally to the screen.
6. Building the Repository
Let's construct the Repository. We pass ourUserDao (Room) and our ApiService (Retrofit) into its constructor.
kotlin
7. Refactoring the ViewModel
Now look at how incredibly clean our ViewModel becomes! It has zero Retrofit code and zero Room connection code. It just delegates to the Repository.
kotlin
8. The Complete MVVM Flow
You have now constructed a professional Android architecture:- 1. Activity/Fragment: Captures user clicks and renders the UI. Observes the ViewModel.
- 2. ViewModel: Survives rotation. Holds LiveData. Delegates actions to the Repository.
- 3. Repository: The data traffic controller. Decides when to fetch from API vs. DB.
- 4. Room DAO (Local): The SQLite database cache (Single Source of Truth).
- 5. Retrofit (Remote): The internet API.
9. Common Mistakes
-
Bypassing the Repository: Often, developers will write a quick database query directly inside an Activity because it's "faster" than creating a function in the Repository and ViewModel. This instantly breaks the architecture. All data operations MUST strictly flow:
Activity -> ViewModel -> Repository -> Data Source.
-
Memory Leaks via Context: Passing an Activity
Contextinto a Repository. Repositories should ideally be context-agnostic. If Room requires a context, pass theApplicationContextvia theAndroidViewModel, never the Activity context.
10. Best Practices
- Dependency Injection (Hilt/Dagger): In our example, the ViewModel manually created the Repository. In enterprise apps, the Repository is "Injected" into the ViewModel constructor automatically using a framework like Hilt. This makes mocking and Unit Testing significantly easier.
-
Data Mapping: An API might return a JSON object with 50 fields, but your Database only needs 5 fields. The Repository is the perfect place to execute Data Mapping, converting a complex
NetworkUserDtointo a leanLocalUserEntitybefore saving it to Room.
11. Exercises
- 1. Draw a flowchart on a piece of paper illustrating the MVVM Repository pattern. Label the arrows denoting where data flows, and where LiveData is observed.
-
2.
In your own project, create a
NoteRepositorythat takes aNoteDao. Move theinsertNotelogic out of the ViewModel and into the Repository.
12. Coding Challenges
Challenge: Implement a caching timeout mechanism in the Repository. Modify the Repository so that whenrefreshUsersFromNetwork() is called, it checks a local variable lastFetchTime. If the last fetch was less than 5 minutes ago, it simply returns and does *not* make a Retrofit call, saving user bandwidth!
13. MCQ Quiz with Answers
Question 1
In the context of Android Clean Architecture, what is the primary structural responsibility of the Repository class?
Question 2
When implementing the "Single Source of Truth" strategy utilizing Room and Retrofit, how does the UI receive newly downloaded network data?
14. Interview Questions
- Q: Explain the Single Responsibility Principle as it relates to the decoupling of the ViewModel and the Repository. Why is it an anti-pattern for a ViewModel to instantiate a Retrofit client directly?
-
Q: Detail the "Single Source of Truth" caching paradigm. How does returning
LiveDatadirectly from a Room DAO facilitate seamless offline-first synchronization during a network fetch?
- Q: Describe the concept of Data Mapping (DTOs to Entities). Why is it architecturally beneficial for the Repository to perform this mapping rather than the ViewModel or the UI controller?