December 26, 2019

1321 words 7 mins read

igorwojda/android-showcase

igorwojda/android-showcase

Android application following best practices: Kotlin, coroutines, Clean Architecture, feature modules, tests, MVVM, static analysis…

repo name igorwojda/android-showcase
repo link https://github.com/igorwojda/android-showcase
homepage
language Kotlin
size (curr.) 5375 kB
stars (curr.) 2345
created 2018-11-20
license MIT License

Project description

CircleCI Kotlin Version API

codebeat badge Codacy Badge CodeFactor

Showcase is a sample project that presents modern, 2020 approach to Android application development using Kotlin and latest tech-stack.

The goal of the project is to demonstrate best practices, provide a set of guidelines, and present modern Android application architecture that is modular, scalable, maintainable and testable. This application may look simple, but it has all of these small details that will set the rock-solid foundation of the larger app suitable for bigger teams and long application lifecycle. Many of the project design decisions follow official Google recommendations.

This project is being heavily maintained to match current industry standards. In upcoming weeks I plan to write an extensive series of articles explaining many of this project architectural design decisions , so stay tuned.

Project characteristics

This project brings to table set of best practices, tools, and solutions:

  • 100% Kotlin
  • Modern architecture (feature modules, Clean Architecture, Model-View-ViewModel, Model-View-Intent)
  • Android Jetpack
  • A single-activity architecture, using the Navigation component to manage fragment operations
  • Reactive UI
  • CI pipeline
  • Testing
  • Static analysis tools
  • Dependency Injection
  • Material design

Tech-stack

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.

Architecture

Feature related code is placed inside one of the feature modules. This modularized approach provides better separation of concerns in the codebase and allows for feature to be developed in isolation, independently from other features.

Module dependencies

This is a simplified diagram of dependencies between gradle modules.

module_dependencies

Clean architecture is the “core architecture” of the application. Each feature module contains own set of Clean architecture layers. app module structure is a bit different, because it mostly contains “fundamental app configuration” (dependency injection, application class, retrofit configurations, etc.) and code that wire multiple module together (eg. NavHostActivity).

Note that due usage of Android dynamic-feature module dependencies are reversed (feature modules are depending on app module, not another way around).

feature_structure

Each layer has a distinct set of responsibilities:

  • Presentation layer - presents data to a screen and handle user interactions
  • Domain layer - contains business logic
  • Data layer - access, retrieve and manage application data

feature_structure

Presentation layer is as mix of MVVM (Jetpack ViewModel used to preserve data across activity restart) and MVI (actions modify common state of the view and then new state is edited to a view via LiveData to be rendered).

common state (for each view) approach derives from Unidirectional Data Flow and Redux principles.

Data flow

Below diagram presents application data flow when a user interacts with album list screen:

app_data_flow

Ci pipeline

CI pipeline verifies project correctness which each PR. Some of the tasks run in parallel, while others like app build will not be stared until all static checks and tests complete successfully:

ci_pipeline.jpg

These are all of the Gradle tasks (cmd commands) that are executed by CI:

  • ./gradlew lintDebug - runs Android lint
  • ./gradlew detekt - runs detekt
  • ./gradlew ktlintCheck - runs ktlint
  • ./gradlew testDebugUnitTest - run unit tests
  • ./gradlew :app:bundleDebug - create app bundle

On top of that project contains custom ./gradlew staticCheck task that mimics all CI tasks and is intended to run on local computer.

Design decisions

Read related articles to have better understanding of underlying design decisions and various trade offs.

What this project does not cover?

The interface of the app utilises some of modern material design components, however, is deliberately kept simple to focus on application architecture.

Upcoming improvements

  • Add test coverage support (Jacoco)
  • Improve error handling
  • Improve multi-module navigation
  • UI tests (including CI pipeline emulator configuration)
  • Caching layer (memory + disk)
  • Android Dynamic delivery
  • Add Room
  • Data binding
  • Add Custom android lint, ktlint and detekt checks/rules
  • Add script to update all dependencies in the project, create PR to run all checks
  • Continuous deployment (automatically publish app to Google play store using CI)
  • Support for DayNight MaterialTheme
  • and much more…

Getting started

There are a few ways to open this project.

Android Studio

  1. Android Studio -> File -> New -> From Version control -> Git
  2. Enter https://github.com/igorwojda/android-showcase.git into URL field

Command line + Android Studio

  1. Run git clone https://github.com/igorwojda/android-showcase.git
  2. Android Studio -> File -> Open

Inspiration

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.

Projects

Other high-quality projects will help you to find solutions that works for your project:

Known issues

  • ktlint ignores multiple file extensions when space is present in .editorconfig (Fixed in upcoming 0.34.2+ release)
  • ktlint import-ordering rule conflicts with IDE default formatting rule, so it have to be disabled
  • Classes generated by SafeArgs plugin (AlbumListFragmentDirections, AlbumDetailFragmentArgs…) are not properly recognized by IDE in the multi-module configuration. Code will run however IDE will mark these classes as non- existing. Also sometimes code has to be cleaned before running tests. This needs more investigation.
  • False positive “Unused symbol” for a custom Android application class referenced in AndroidManifest.xml file (Issue)
  • False positive “Function can be private” (Issue)
  • Gradle Kotlin Script is not fully supported by Android Studio
  • Unit tests are running in IDE but fail after running gradle task because of missing Agrs class (Issue)

Contribute

Feedback and new contributions are welcome whether it’s through bug reports or new PRs.

Author

Follow me

Follow me

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 and are distributed under Creative Commons License 2.0:

comments powered by Disqus