Coding Studio

Learn & Grow together.

Android Clean Architecture Explained (With Practical Examples)

Modern Android apps quickly become complex. Without a proper structure, Activities and ViewModels turn into massive, unmaintainable classes.

This is where Clean Architecture becomes a game changer.

In this guide, you’ll learn:

✔ What Clean Architecture is
✔ Why it matters in Android development
✔ Layered structure explained
✔ Dependency rules
✔ Practical Kotlin examples
✔ Common mistakes to avoid


✅ What is Clean Architecture?

Clean Architecture is a software design pattern that separates an application into distinct layers, ensuring:

  • Clear separation of concerns
  • Framework independence
  • High testability
  • Scalability & maintainability

Core philosophy:

Business logic should not depend on UI, databases, or frameworks.


✅ Why Clean Architecture is Important in Android

Without architecture:

❌ UI & logic tightly coupled
❌ Hard to test
❌ Difficult to scale
❌ Fragile codebase

With Clean Architecture:

✅ Testable business rules
✅ Flexible technology choices
✅ Clean & modular code
✅ Easier debugging


✅ The Three Core Layers

Android Clean Architecture typically consists of:

  1. Presentation Layer
  2. Domain Layer
  3. Data Layer

Each layer has a distinct responsibility.



🟢 1. Presentation Layer (UI & State Management)

Responsible for:

✔ Displaying UI
✔ Handling user actions
✔ Managing UI state

Contains:

  • Activities / Fragments / Composables
  • ViewModels
  • UI State classes

Example structure:

presentation/
├── ui/
├── viewmodel/
└── state/

✅ Example ViewModel

class UserViewModel(
private val getUserProfileUseCase: GetUserProfileUseCase
) : ViewModel() { private val _state = MutableStateFlow<UserState>(UserState.Loading)
val state: StateFlow<UserState> = _state fun loadUser(userId: String) {
viewModelScope.launch {
try {
val user = getUserProfileUseCase(userId)
_state.value = UserState.Success(user)
} catch (e: Exception) {
_state.value = UserState.Error(e.message ?: "Unknown error")
}
}
}
}

✅ UI State Representation

sealed class UserState {
object Loading : UserState()
data class Success(val user: User) : UserState()
data class Error(val message: String) : UserState()
}

👉 Notice: No API / DB logic here.



🟡 2. Domain Layer (Core Business Logic)

The most important layer.

Responsible for:

✔ Business rules
✔ Use cases
✔ Core models
✔ Framework independence

Contains:

  • UseCases
  • Domain Models
  • Repository Interfaces

Example structure:

domain/
├── model/
├── repository/
└── usecase/

✅ Domain Model Example

data class User(
val id: String,
val name: String,
val email: String
)

Pure Kotlin → No Retrofit / Room / Android.


✅ Use Case Example

class GetUserProfileUseCase(
private val repository: UserRepository
) {
suspend operator fun invoke(userId: String): User {
return repository.getUser(userId)
}
}

UseCases encapsulate single business actions.


✅ Repository Interface

interface UserRepository {
suspend fun getUser(userId: String): User
}

👉 Domain defines contract, not implementation.



🔵 3. Data Layer (Implementation Details)

Responsible for:

✔ API calls
✔ Database operations
✔ Mapping models
✔ Repository implementations

Example structure:

data/
├── remote/
├── local/
├── mapper/
└── repository/

✅ API DTO Example

data class UserDto(
val id: String,
val full_name: String,
val email_address: String
)

✅ Mapper Example

fun UserDto.toDomain(): User {
return User(
id = id,
name = full_name,
email = email_address
)
}

DTO → Domain Model conversion is critical.


✅ Repository Implementation

class UserRepositoryImpl(
private val api: UserApi
) : UserRepository { override suspend fun getUser(userId: String): User {
return api.getUser(userId).toDomain()
}
}

✅ Dependency Flow (Very Important)

Data flow:

UI → ViewModel → UseCase → Repository → Data Sources

Dependency rule:

Presentation → Domain → Data

Never:

Domain → Android ❌
Domain → Retrofit ❌

✅ Key Benefits of Clean Architecture


✅ 1. High Testability

Domain layer = Pure Kotlin → Easy unit tests.


✅ 2. Scalability

Project grows → Layers remain manageable.


✅ 3. Replaceable Technologies

Swap:

✔ Retrofit → Ktor
✔ Room → SQLDelight
✔ XML → Compose

Without rewriting business logic.


✅ 4. Cleaner Codebase

Responsibilities are predictable & isolated.


✅ Common Mistakes Developers Make

Avoid these:

❌ Business logic inside ViewModel
❌ API models used as domain models
❌ Skipping UseCases in complex apps
❌ Domain layer depending on frameworks


✅ When Should You Use Clean Architecture?

Best for:

✅ Medium & Large apps
✅ Long-term projects
✅ Team-based development
✅ Complex business logic

Overkill for:

✔ Tiny apps
✔ Prototypes / POCs


✅ Mental Model to Remember

Think of layers like:

🏛 Presentation = UI layer
🧠 Domain = Brain / logic
🔌 Data = External systems

Thanks for reading..

Leave a Reply

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