android-showcase
A production-ready Android application demonstrating modern development practices and architectural patterns. This project showcases how to build scalable, maintainable, and testable Android applications using industry-standard tools and libraries.
Built with Clean Architecture principles, this app serves as a comprehensive example of modular design, advanced Gradle configuration, and robust CI/CD practices. Perfect for teams looking to establish solid architectural foundations for large-scale Android projects.
- 💎 Android Showcase 2.0
Application Scope
A music discovery app built with Jetpack Compose that displays album information sourced from the Last.fm API. The application demonstrates real-world scenarios including network requests, local caching, navigation, and state management.
Features:
- Album List - Browse albums with search functionality
- Album Details - View detailed album information and track listings
- Favorites - Save preferred albums (WIP)
- Profile - User preferences and settings (WIP)
Tech-Stack
Built with modern Android development tools and libraries, prioritizing, project structure stability and production-readiness.
Core Technologies:
- Kotlin 2.2+ - Modern, expressive programming language
- Coroutines - Asynchronous programming
- Flow - Reactive data streams
- KSP (Kotlin Symbol Processing) - Kotlin Symbol Processing
- Serialization - JSON parsing
Android Jetpack:
- Compose - Declarative UI framework
- Navigation Compose - Type-safe navigation
- ViewModel - UI-related data management
- Room - Local database with SQLite
Networking & Images:
Dependency Injection:
- Koin - Lightweight dependency injection framework
Architecture:
- Clean Architecture - Separation of concerns with defined layers
- Single Activity Architecture - Modern navigation approach
- MVVM + MVI - Reactive presentation layer pattern providing common UI state.
- Modular Design - Feature-based modules for scalability
UI & Design:
- Material Design 3 - Latest design system
- Dynamic Theming - Wallpaper-based themes (Android 12+)
- Dark Theme - System-aware dark mode
- Lottie - Vector animations
Testing:
- JUnit 5 - Modern testing framework
- Mockk - Kotlin-first mocking library
- Kluent - Fluent assertion library
- Espresso - UI testing (WIP)
Code Quality:
- Konsist - Architecture and code structure convention tests
- Ktlint - Kotlin code formatting and issue detection
- Ktlint Standard Rules - set of custom rules for Jetpack Compose
- Nlopez Jetpack Compose Rules - set of custom rules for Jetpack Compose
- Twitter's Jetpack Compose Rules - set of custom rules for Jetpack Compose
- Detekt - Static analysis and complexity checks
- Android Lint - Android-specific code analysis
- Spotless - Code formatting enforcement
Build & CI:
- Gradle Kotlin DSL - Type-safe build scripts
- Version Catalogs - Centralized dependency management
- Convention Plugins - Shared build logic
- Renovate - Automated dependency updates
GitHub Actions:
- Check - CI pipeline with build, lint, test, and code quality checks
- Auto Approve - Auto-approval for trusted bot and maintainer PRs
- Claude Code - AI-powered code assistance and review
- Claude Code Review - Automated PR reviews using Claude
Gradle Plugins:
- Android Application (
com.android.application
) - Android app module configuration - Android Library (
com.android.library
) - Android library module configuration - Kotlin Android (
org.jetbrains.kotlin.android
) - Kotlin compilation for Android - Kotlin Serialization (
org.jetbrains.kotlin.plugin.serialization
) - JSON serialization support - Kotlin Compose Compiler (
org.jetbrains.kotlin.plugin.compose
) - Compose compiler plugin - KSP - Kotlin Symbol Processing
- Detekt - Static code analysis
- Spotless - Code formatting
- Test Logger - Enhanced test log output
- Easylauncher - Modify the launcher icon of each of your app-variants
- AboutLibraries - collects dependency details, including licenses and visualize these in the app
Architecture
The project implements Clean Architecture with a modular approach, treating each feature as an independent, reusable component similar to a microservice. This design enables maintainability and scalability for large development teams.
Benefits of Modular Architecture:
- Reusability - Shared code across multiple app variants
- Separation of Concerns - Clear module boundaries with explicit dependencies
- Parallel Development - Teams can work on features independently
- Faster Build Times - Incremental compilation and build caching
- Testability - Isolated testing of individual components
Module Types and Dependencies
Module Types:
app
- Main application module containing navigation setup, DI configuration, and app-level componentsfeature-*
- Feature modules (album, profile, favourite) containing feature-specific business logicfeature-base
- Shared foundation module providing common utilities and base classeslibrary-*
- Utility modules for testing and shared functionality
Feature Module Structure
Clean Architecture
is implemented at the module level - each module contains its own set of Clean Architecture layers:
Notice that the
app
module andlibrary_x
modules structure differs a bit from the feature module structure.
Each feature module contains 3 layers with a distinct set of responsibilities and common module components.
Presentation Layer
This layer is closest to what the user sees on the screen.
The presentation
layer mixes MVVM
and MVI
patterns:
MVVM
- JetpackViewModel
is used to encapsulate acommon UI state
. It exposes thestate
via observable state holder (Kotlin Flow
)MVI
-action
modifies thecommon UI state
and emits a new state to a view viaKotlin Flow
The
common state
is a single source of truth for each view. This solution derives from Unidirectional Data Flow) and Redux principles.
This approach facilitates the creation of consistent states. The state is collected via collectAsUiStateWithLifecycle
method. Flows collection happens in a lifecycle-aware manner, so
no resources are wasted.
Stated is annotated with Immutable annotation that is used by Jetpack compose to enable composition optimizations.
Components:
- Screen (Composable) - observes common view state (through
Kotlin Flow
). Compose transform state (emitted by Kotlin Flow) into application UI Consumes the state and transforms it into application UI (viaJetpack Compose
). Pass user interactions toViewModel
. Views are hard to test, so they should be as simple as possible. - ViewModel - emits (through
Kotlin Flow
) view state changes to the view and deals with user interactions (these view models are not simply POJO classes). - ViewState - common state for a single view
- StateTimeTravelDebugger - logs actions and view state transitions to facilitate debugging.
- NavManager - singleton that facilitates handling all navigation events inside
NavHostActivity
(instead of separately, inside each view)
Domain Layer
This is the core layer of the application. Notice that the domain
layer is independent of any other layers. This
allows making domain models and business logic independent from other layers. In other words, changes in other layers
will not affect the domain
layer eg. changing the database (data
layer) or screen UI (presentation
layer) ideally will
not result in any code change within the domain
layer.
Components:
- UseCase - contains business logic
- DomainModel - defines the core structure of the data that will be used within the application. This is the source of truth for application data.
- Repository interface - required to keep the
domain
layer independent from thedata layer
(Dependency inversion).
Data Layer
Encapsulates application data. Provides the data to the domain
layer eg. retrieves data from the internet and cache the
data in disk cache (when the device is offline).
Components:
- Repository is exposing data to the
domain
layer. Depending on the application structure and quality of the external API repository can also merge, filter, and transform the data. These operations intend to create a high-quality data source for thedomain
layer. It is the responsibility of the Repository (one or more) to construct Domain models by reading from theData Source
and accepting Domain models to be written to theData Source
- Mapper - maps
data model
todomain model
(to keepdomain
layer independent from thedata
layer).
This application has two Data Sources
- Retrofit
(used for network access) and Room
(local storage used to access
device persistent memory). These data sources can be treated as an implicit sub-layer. Each data source consists of
multiple classes:
- Retrofit Service - defines a set of API endpoints
- Retrofit Response Model - definition of the network objects for a given endpoint (top-level model for the data
consists of
ApiModels
) - Retrofit Api Data Model - defines the network objects (sub-objects of the
Response Model
) - Room Database - persistence database to store app data
- Room DAO - interact with the stored data
- Room Entity - definition of the stored objects
Both Retrofit API Data Models
and Room Entities
contain annotations, so the given framework understands how to parse the
data into objects.
Common Module Components
Each module in the Android project contains several standard items that provide essential functionality and configuration:
Components:
- Gradle Build Script -
build.gradle.kts
defining dependencies, build configurations, and plugins. - Koin DI Module - Dependency injection configuration
- Tests - Unit tests (
test/
) and integration tests (androidTest/
) - Android Resources - resources (
res/
) including strings, drawables, and assets. - Android Manifest - The
AndroidManifest.xml
file declaring module metadata.
Data Flow
The below diagram presents application data flow when a user interacts with the album list screen
:
Project Features
Development & Debugging
Tags (LogTags) help filter and identify different types of logs during development and debugging.
The app provides detailed logging for development and debugging, with each log easily filterable by its tag:
Navigation
- Navigation events and route changesAction
- User actions and UI state modificationsNetwork
- Network requests, responses, and HTTP-related logs
Custom Icons For Each Variant
Thanks to Easylauncher Gradle plugin the debug
build has custom icon label:
Themed Icons
App supports Themed Icons.
Left (classic icon), Right (themed icon):
Gradle Config
Dependency Management
Gradle versions catalog is used as a centralized dependency management third-party dependency coordinates (group, artifact, version) are shared across all modules (Gradle projects and subprojects).
Gradle versions catalog consists of a few major sections:
[versions]
- declare versions that can be referenced by all dependencies[libraries]
- declare the aliases to library coordinates[bundles]
- declare dependency bundles (groups)[plugins]
- declare Gradle plugin dependencies
Each module uses convention a plugin, so common dependencies are shared without the need to add them explicitly in each module.
Convention Plugins
Convention plugins standardize build configuration across modules by encapsulating common build logic into reusable plugins:
Application Convention
- Main application module configuration with Android app setupFeature Convention
- Feature module configuration combining library and Kotlin conventionsLibrary Convention
- Android library module setup with common Android configurationLotlin Convention
- Kotlin compilation settings, toolchain, and compiler optionsTest Convention
- Testing framework setup (JUnit 5, test logging, and test configurations)Test Library Convention
- Testing setup specifically for library modulesDetekt Convention
- Static code analysis configuration with DetektSpotless Convention
- Code formatting and style enforcement with SpotlessEasylauncher Convention
- App icon customization for different build variantsAboutLibraries Convention
- About libraries configuration
Type Safe Project Accessors
Enables type-safe project references instead of error-prone string-based module paths:
// Before
implementation(project(":feature:album"))
// After
implementation(projects.feature.album)
Unified Version Configuration
All dependency and Gradle plugin versions are defined in the TOML version catalog file (libs.versions.toml).
Java/JVM Version Configuration
The Java/JVM version is centralized across the project.
It is defined once in libs.versions.toml
file under the java entry.
The generateJavaBuildConfig
task reads this value and generates a JavaBuildConfig.kt
file with constants.
These constants are then used in Gradle convention plugins to configure both Java and Kotlin consistently:
compileOptions {
sourceCompatibility = JavaBuildConfig.JAVA_VERSION
targetCompatibility = JavaBuildConfig.JAVA_VERSION
}
kotlin {
compilerOptions {
jvmTarget = JavaBuildConfig.jvmTarget
}
jvmToolchain(JavaBuildConfig.jvmToolchainVersion)
}
Generated type-safe version catalogs accessors in buildLogic
module
Type-safe version catalogs accessors are accessible from precompiled script plugins in the buildLogic
module. This is configured through the versionCatalogs
block in buildLogic/settings.gradle.kts
which references the main version catalog file, enabling access to dependencies like:
add("implementation", libs.koin)
Code Verification
Quality Checks:
./gradlew konsistTest:test --rerun-tasks # Architecture & convention validation
./gradlew lintDebug # Android lint analysis
./gradlew detektCheck # Code complexity & style analysis
./gradlew spotlessCheck # Code formatting verification
./gradlew testDebugUnitTest # Unit test execution
./gradlew connectedCheck # UI test execution (WIP)
./gradlew :app:bundleDebug # Production build verification
Auto-fix Commands:
./gradlew detektApply # Apply Detekt formatting fixes
./gradlew spotlessApply # Apply code formatting fixes
./gradlew lintDebug # Update lint baseline
CI Pipeline
GitHub Actions workflows execute quality checks automatically:
- PR Validation - All checks run in parallel on pull requests
- Main Branch Protection - Post-merge validation ensures code quality
- Automated Dependency Updates - Renovate bot creates PRs for dependency updates
Configuration: .github/workflows
Pre-push Hooks
Optional Git hooks can execute quality checks before pushing code, providing fast feedback during development.
Project Scope & Limitations
This showcase prioritizes architecture, tooling, and development practices over complex UI design. The interface uses Material Design 3 components but remains intentionally straightforward to focus on the underlying technical implementation.
Getting Started
Prerequisites:
- Android Studio Giraffe | 2022.3.1+
- JDK 17+
- Android SDK 34+
Setup:
# Clone the repository
git clone https://github.com/igorwojda/android-showcase.git
# Open in Android Studio
# File -> Open -> Select cloned directory
Recommended IDE Plugins:
- Detekt - Configure with detekt.yml
- Kotlin - Usually pre-installed
- Android - Usually pre-installed
Roadmap
Active development continues with focus on modern Android practices. View planned enhancements and contribute ideas.
Resources
Development Tools:
- Material Theme Builder - Generate Material 3 dynamic themes
- Compose Material 3 Components - Component reference
- Android Ecosystem Cheat Sheet - 200+ essential Android tools
- Kotlin Coroutines Use Cases - Practical coroutine examples
Recommended Projects:
- Now in Android - Google's official modern Android showcase
- Android Architecture Blueprints - Architecture pattern examples
- Compose Samples - Official Jetpack Compose examples
- Kotlin Android Template - Pre-configured project template
- Androidify - Android's official character customization app
- WeatherXM Android - Weather data collection and rewards platform
- Songify - Spotify-inspired music streaming app
- Alkaa - Task management app with modern architecture
- KotlinConf App - JetBrains' official conference app
- Tivi - TV show tracking app by Chris Banes
- CatchUp - News aggregation app with modular architecture
- Heron - Social media client showcasing modern Android development
Contributing
Contributions are welcome! Please check the CONTRIBUTING.md guidelines before submitting PRs.
Areas for Contribution:
- Feature implementations (Profile, Favorites screens)
- UI/UX improvements and animations
- Performance optimizations
- Testing coverage expansion
- Documentation improvements
Author
Igor Wojda - Senior Android Engineer
License
MIT License
Copyright (c) 2019 Igor Wojda
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Animations License
Flowing animations are distributed under Creative Commons License 2.0
:
- Error screen by Chetan Potnuru
- Building Screen by Carolina Cajazeira