Showcase is a sample project that presents a modern, 2020 approach to Android application development with up to date tech-stack.
The goal of the project is to demonstrate best practices by using up to date tech-stack and presenting mod ern Android application Architecture that is modular, scalable, maintainable, and testable. This application may look quite simple, but it has all of these small details that will set the rock-solid foundation for the larger app suitable for bigger teams and long application lifecycle.
This project is being maintained to match current industry standards. Please check CONTRIBUTING page if you want to help.
This project brings to table set of best practices, tools, and solutions:
- 100% Kotlin
- Modern architecture (dynamic feature modules, Clean Architecture, Model-View-ViewModel, Model-View-Intent)
- Android Jetpack
- A single-activity architecture (Navigation component)
- Reactive UI
- CI pipeline (GitHub Actions)
- Testing (Unit, UI)
- Static analysis tools
- Dependency Injection
- Material design
Min API level is set to
21, so the presented approach is suitable for over 85% of devices running Android. This project takes advantage of many popular libraries and tools of the Android ecosystem. Most of the libraries are in the stable version unless there is a good reason to use non-stable dependency.
- Kotlin + Coroutines - perform background operations
- Kodein - dependency injection
- Retrofit - networking
- Coil - image loading library with Kotlin idiomatic API
- Lottie - animation library
- Stetho - application debugging tool
- and more...
Feature related code is placed inside one of the feature modules. We can think about each feature as the equivalent of microservice or private library.
The modularized code-base approach provides few benefits:
- better separation of concerns. Each module has a clear API., Feature related classes life in different modules and can't be referenced without explicit module dependency.
- features can be developed in parallel eg. by different teams
- each feature can be developed in isolation, independently from other features
- faster compile time
Module types and module dependencies
This is a diagram present dependencies between project modules (Gradle sub-projects).
Note that due usage of Android
dynamic-feature module dependencies are reversed (feature modules are depending on
app module, not another way around).
We have three kinds of modules in the application:
appmodule - this is the main module. It contains code that wires multiple modules together (dependency injection setup,
NavHostActivity, etc.) and fundamental application configuration (retrofit configuration, required permissions setup, custom application class, etc.).
- helper modules
library_basemodule containing common code base that could be reused in other projects/applications (this code is not specific to this application) eg. base classes, utilities, custom delegates, extensions.
- additional application-specific
library_xmodules that some of the features could depend on. This is helpful if you want to share some assets or code only between few feature modules (currently app has no such modules)
- feature modules - the most common type of module containing all code related to a given feature.
Feature module structure
Clean architecture is the "core architecture" of the application, so each
feature module contains own set of Clean architecture layers:
library_xmodules structure differs a bit from feature module structure.
Each feature module contains non-layer components and 3 layers with distinct set of responsibilities.
This layer is closest to what the user sees on the screen. The
presentation layer is a mix of
ViewModel used to preserve data across activity restart) and
actions modify the
common state of the view and then new state is edited to a view via
LiveData to be rendered).
- View (Fragment) - presents data on the screen and pass user interactions to View Model. Views are hard to test, so they should be as simple as possible.
- ViewModel - dispatches (through
LiveData) 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
- NavManager - singleton that facilitates handling all navigation events inside
NavHostActivity(instead of separately, inside each view)
This is the core layer of the application. Notice that the
domain layer is independent of any other layers. This allows to make domain models and business logic independent from other layers. In other words, changes in other layers will have no effect on
domain layer eg. changing database (
data layer) or screen UI (
presentation layer) ideally will not result in any code change withing
- UseCase - contains business logic
- DomainModel - defies 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
domainlayer independent from the
data layer(Dependency inversion).
Manages application data and exposes these data sources as repositories to the
domain layer. Typical responsibilities of this layer would be to retrieve data from the internet and optionally cache this data locally.
Repository is exposing data to the
domainlayer. Depending on application structure and quality of the external APIs repository can also merge, filter, and transform the data. The intention of these operations is to create high-quality data source for the
domainlayer, not to perform any business logic (
Mapper - maps
domain model(to keep
domainlayer independent from the
RetrofitService - defines a set of API endpoints.
DataModel - defines the structure of the data retrieved from the network and contains annotations, so Retrofit (Moshi) understands how to parse this network data (XML, JSON, Binary...) this data into objects.
Below diagram presents application data flow when a user interacts with
album list screen:
All the external dependencies (external libraries) are defined in the single place - Gradle
buildSrc folder. This approach allows to easily manage dependencies and use the same dependency version across all modules. Because each feature module depends on the
app module we can easily share all core dependencies without redefining them in each feature module.
CI pipeline verifies project correctness which each PR. All of the tasks run in parallel:
These are all of the Gradle tasks that are GitHub Actions:
./gradlew lintDebug- runs Android lint
./gradlew detekt- runs detekt
./gradlew ktlintCheck- runs ktlint
./gradlew testDebugUnitTest- run unit tests
./gradlew connectedCheck- run UI tests
./gradlew :app:bundleDebug- create app bundle
Read related articles to have a better understanding of underlying design decisions and various trade-offs.
- Multiple ways of defining Clean Architecture layers
- More coming soon
What this project does not cover?
The interface of the app utilizes some of the modern material design components, however, is deliberately kept simple to focus on application architecture.
Checklist of all upcoming enhancements.
There are a few ways to open this project.
- Android Studio -> File -> New -> From Version control -> Git
https://github.com/igorwojda/android-showcase.gitinto URL field
Command-line + Android Studio
git clone https://github.com/igorwojda/android-showcase.git
- Android Studio -> File -> Open
This is project is a sample, to inspire you and should handle most of the common cases, but please take a look at additional resources.
- Android Ecosystem Cheat Sheet - board containing 200+ most important tools
- Kotlin Coroutines - Use Cases on Android - most popular coroutine usages
Other high-quality projects will help you to find solutions that work for your project:
- Iosched - official Android application from google IO 2019
- Android Architecture Blueprints v2 - a showcase of various Android architecture approaches
- Android sunflower complete
Jetpacksample covering all libraries
- GithubBrowserSample - multiple small projects demonstrating usage of Android Architecture Components
- Plaid - a showcase of Android material design
- Clean Architecture boilerplate - contains nice diagrams of Clean Architecture layers
- Android samples - official Android samples repository
- Roxie - solid example of
common stateapproach together witch very good documentation
- Kotlin Android template - template that lets you create an Android/Kotlin project and be up and running in a few seconds.
import-orderingrule conflicts with IDE default formatting rule, so it have to be disabled
- False positive "Unused symbol" for a custom Android application class referenced in AndroidManifest.xml file (Issue)
- False positive "Function can be private" (Issue)
- Unit tests are running in IDE but fail after running gradle task because of missing Agrs class (Issue)
Want to contribute? Check our Contributing docs.
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.
Flowing animations and are distributed under
Creative Commons License 2.0: