Skip to content

jackhoang2411/PracticeArchitecture

Repository files navigation

News Reader — Learn Android Architecture Step by Step

A hands-on learning project that teaches modern Android development by building a News Reader app from scratch in 10 incremental steps. Each step introduces one concept, keeps the app runnable, and is backed by detailed documentation.

By the end you'll have a fully working app with Jetpack Compose UI, ViewModel + StateFlow, Hilt DI, Retrofit networking, Room caching, Navigation, pull-to-refresh, and unit tests — all wired together following the recommended Android architecture.


Who is this for?

  • Android developers who want to learn Jetpack Compose and modern architecture (MVVM, Repository pattern, single source of truth).
  • Developers moving from XML-based Android to Compose.
  • Anyone who prefers learning by building a real app rather than reading docs in isolation.

Tech stack

Layer Library Purpose
UI Jetpack Compose, Material 3 Declarative UI, theming, pull-to-refresh
State ViewModel + StateFlow Lifecycle-aware, reactive state management
DI Hilt Compile-time dependency injection
Network Retrofit + OkHttp REST API calls to NewsAPI.org
Local DB Room SQLite caching with Flow-based queries
Navigation Navigation Compose + Hilt Navigation Type-safe routes, argument passing
Async Kotlin Coroutines + Flow Structured concurrency
Testing JUnit 4 + kotlinx-coroutines-test ViewModel unit tests with fake repository

Prerequisites

  • Android Studio (latest stable — Ladybug or newer recommended)
  • Kotlin 2.0+ (this project uses 2.0.21)
  • JDK 11+
  • A free API key from NewsAPI.org (sign up takes 30 seconds)

Getting started

1. Clone the repo

git clone https://github.com/jackhoang2411/PracticeArchitecture.git
cd PracticeArchitecture

2. Add your API key

Create (or edit) local.properties in the project root and add:

NEWS_API_KEY=your_api_key_here

local.properties is gitignored — your key stays private.

3. Open in Android Studio

Open the project folder in Android Studio. Gradle will sync automatically.

4. Run the app

Select a device or emulator and hit Run (or ./gradlew installDebug).

5. Run the tests

./gradlew :app:testDebugUnitTest

Project structure

app/src/main/java/com/example/learningarchitect/
├── domain/
│   ├── model/          Article (domain model)
│   └── repository/     NewsRepository (interface)
├── data/
│   ├── remote/
│   │   ├── dto/        ArticleDto, NewsApiResponse, SourceDto
│   │   ├── mapper/     ArticleDto → Article mapping
│   │   └── NewsApiService.kt  (Retrofit interface)
│   ├── local/
│   │   ├── entity/     ArticleEntity (Room)
│   │   ├── dao/        ArticleDao
│   │   ├── mapper/     Entity ↔ Domain mapping
│   │   └── AppDatabase.kt
│   └── repository/
│       ├── DefaultNewsRepository.kt  (real: API + Room)
│       └── FakeNewsRepository.kt     (sample data)
├── di/
│   ├── AppModule.kt        (binds NewsRepository)
│   ├── NetworkModule.kt    (Retrofit, OkHttp)
│   ├── DatabaseModule.kt   (Room)
│   └── Qualifiers.kt       (@NewsApiKey)
├── ui/
│   ├── screens/
│   │   ├── NewsScreen.kt / NewsViewModel.kt / NewsUiState.kt
│   │   └── ArticleDetailScreen.kt / ArticleDetailViewModel.kt
│   ├── navigation/
│   │   ├── Routes.kt
│   │   └── NewsNavGraph.kt
│   └── theme/              Color, Type, Theme
├── MainActivity.kt
└── LearningArchitectApplication.kt  (@HiltAndroidApp)

app/src/test/  (unit tests)
├── data/repository/    FakeNewsRepositoryForTest
└── ui/screens/         NewsViewModelTest

docs/
├── STEP_1.md … STEP_10.md   (detailed write-ups for each step)

The 10 learning steps

Each step builds on the previous one. Every step has a detailed guide in docs/STEP_<N>.md that explains what you're building, why, and the key concepts.

Step What you learn Key files Guide
1 Compose basics — data model, one screen, hardcoded list Article.kt, NewsScreen.kt, MainActivity.kt STEP_1
2 ViewModel + StateFlow — Loading / Success / Error states NewsViewModel.kt, NewsUiState.kt STEP_2
3 Hilt — Application class, modules, constructor injection LearningArchitectApplication.kt, AppModule.kt STEP_3
4 Retrofit — API service, DTOs, network module NewsApiService.kt, NetworkModule.kt, DTOs STEP_4
5 Repository pattern — wire API into ViewModel via interface DefaultNewsRepository.kt, ArticleMapper.kt STEP_5
6 Room — entity, DAO, database, cache API responses ArticleEntity.kt, ArticleDao.kt, AppDatabase.kt STEP_6
7 Cache-first strategy — observe Room Flow, refresh from API getArticlesFlow(), refresh() in repository STEP_7
8 Navigation Compose — detail screen, route arguments, hiltViewModel Routes.kt, NewsNavGraph.kt, ArticleDetailScreen.kt STEP_8
9 Polish — pull-to-refresh, empty state, error UX PullToRefreshBox, isRefreshing in ViewModel STEP_9
10 Testing — unit test ViewModel with fake repository FakeNewsRepositoryForTest.kt, NewsViewModelTest.kt STEP_10

How to use this project to learn

Option A: Follow along from step 1

Check out the git tag for each step and read the matching guide:

git checkout step-1-compose-basics   # start here
# read docs/STEP_1.md, explore the code, run the app

git checkout step-2-viewmodel-state  # next step
# read docs/STEP_2.md ...

At each step, the app compiles and runs. You can see exactly what changed by diffing tags:

git diff step-1-compose-basics..step-2-viewmodel-state

Option B: Read the finished code

Stay on main and browse the full codebase. Use docs/STEP_1.md through docs/STEP_10.md as a guided tour — each one explains the concepts and points to the relevant files.

Option C: Use it as a reference

Looking up how to set up Hilt? Check docs/STEP_3.md and di/. Need a Room caching example? See docs/STEP_6.md and data/local/. Each step is self-contained enough to be a reference for that specific topic.


Architecture diagram

┌─────────────────────────────────────────────────┐
│                    UI Layer                      │
│  NewsScreen ← NewsViewModel ← NewsUiState       │
│  ArticleDetailScreen ← ArticleDetailViewModel   │
│  NewsNavGraph (navigation)                       │
└──────────────────────┬──────────────────────────┘
                       │ collects Flow / calls refresh()
┌──────────────────────▼──────────────────────────┐
│                 Domain Layer                     │
│  NewsRepository (interface)                      │
│  Article (domain model)                          │
└──────────────────────┬──────────────────────────┘
                       │ implemented by
┌──────────────────────▼──────────────────────────┐
│                  Data Layer                      │
│  DefaultNewsRepository                           │
│    ├── NewsApiService (Retrofit) ── remote/      │
│    └── ArticleDao (Room) ──────── local/         │
│                                                  │
│  Cache-first: observe Room Flow, refresh via API │
└─────────────────────────────────────────────────┘

Git tags

All steps are tagged so you can jump to any point:

step-1-compose-basics
step-2-viewmodel-state
step-3-hilt-setup
step-4-retrofit
step-5-repository
step-6-room-cache
step-7-cache-strategy
step-8-navigation
step-9-polish
step-10-testing

Common issues

Problem Solution
NEWS_API_KEY is empty at runtime Make sure local.properties has NEWS_API_KEY=your_key (no quotes). Rebuild the project.
"Cannot create an instance of ViewModel" Use hiltViewModel() (from androidx.hilt:hilt-navigation-compose) instead of viewModel(). See STEP_8.
UncompletedCoroutinesError in tests Don't pass the same dispatcher to both setMain() and runTest(). See STEP_10.
Room schema changed, app crashes Uninstall the app (or bump the database version with a migration).
Compose preview not rendering Make sure preview composables don't depend on Hilt-injected ViewModels. Use hardcoded sample data.

What's next?

The 10-step roadmap is complete. Ideas to keep going:

  • Compose UI tests — use composeTestRule to test screen behavior.
  • Repository integration tests — use an in-memory Room database.
  • Paging — load articles page by page with Paging 3.
  • Image loading — add Coil or Glide for article thumbnails.
  • Offline-first — show cached data immediately, sync in background.
  • Dark theme — the Material 3 theme already supports it; add a toggle.

License

This is a personal learning project. Feel free to use it as a reference or starting point for your own learning.

About

Step-by-step News Reader app teaching modern Android architecture with Compose, Hilt, Room, and tests.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages