bill-bil / android-showcase

πŸ’Ž Android application following best practices: Kotlin, Coroutines, JetPack, Clean Architecture, Feature Modules, Tests, MVVM, DI, Static Analysis...

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

πŸ’Ž Android Showcase 2.0

Kotlin Version AGP Gradle

codebeat badge CodeFactor

Android Showcase project presents a modern approach to Android application development. It is a complete sample of a fully functional Android application.

Project is utilizing modular, scalable, maintainable, and testable architecture, leading tech-stack and demonstrates the best development practices.

This application may look simple, but it has all the pieces that will provide the rock-solid foundation for the larger application suitable for bigger teams during extended application lifecycle.

This project is being maintained to stay up to date with leading industry standards. Please check the CONTRIBUTING page if you want to help.

Application Scope

The android-showcase displays information about music albums. The data is loaded from the Last.fm Music Discovery API.

The app has a few screens located in multiple feature modules:

  • Album list screen - displays list of albums
  • Album detail screen - display information about the selected album
  • Profile screen - empty (WiP)
  • Favourites screen - empty (WiP)

Tech-Stack

This project takes advantage of best practices, and many popular libraries and tools in the Android ecosystem. Most of the libraries are in the stable version unless there is a good reason to use non-stable dependency.

Architecture

By dividing a problem into smaller and easier to solve sub-problems, we can reduce the complexity of designing and maintaining a large system. Each module is independent build-block serving a clear purpose. We can think about each feature as the reusable component, equivalent of microservice or private library.

The modularized code-base approach provides a few benefits:

  • reusability - enable code sharing and building multiple apps from the same foundation. Apps should be a sum of their
  • features where the features are organized as separate modules.
  • separation of concerns - each module has a clear API. Feature-related classes live in different modules and can't be referenced without explicit module dependency. We strictly control what is exposed to other parts of your codebase.
  • features can be developed in parallel eg. by different teams
  • each feature can be developed in isolation, independently from other features
  • faster build time

Module Types And Module Dependencies

This diagram presents dependencies between project modules (Gradle sub-projects).

module_dependencies

We have three kinds of modules in the application:

  • app module - 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.).
  • application-specific library_x modules that some of the features could depend on. This is helpful if you want to share some assets or code only between a 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 its own set of Clean architecture layers:

module_dependencies_layers

Notice that the app module and library_x modules structure differs a bit from the feature module structure.

Each feature module contains non-layer components and 3 layers with a distinct set of responsibilities.

feature_structure

Presentation Layer

This layer is closest to what the user sees on the screen. The presentation layer is a mix of MVVM ( Jetpack ViewModel used to preserve data across activity restart) and MVI (actions modify the common state of the view and then a 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.

Components:

  • View (Fragment) - presents data on the screen and passes user interactions to View Model. Views are hard to test, so they should be as simple as possible.
  • ViewModel - dispatches (through Kotlin Flow) 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)

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 domain layer eg. changing the database (data layer) or screen UI (presentation layer) ideally will not result in any code change withing 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 the data layer (Dependency inversion).

Data Layer

Manages application data. Connect to data sources and provide data through repository to the domain layer eg. retrieve data from the internet and cache the data in disk cache (when device is offline).

Components:

  • Repository is exposing data to the domain layer. Depending on the application structure and quality of the external APIs repository can also merge, filter, and transform the data. These operations intend to create high-quality data source for the domain layer, not to perform any business logic (domain layer use case responsibility).

  • Mapper - maps data model to domain model (to keep domain layer independent from the data layer).

  • 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.

Data Flow

The below diagram presents application data flow when a user interacts with the album list screen:

app_data_flow

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).

All of the dependencies are stored in the libs.versions.toml file (default location). The TOML file 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 feature module depends on the feature_base module, so dependencies are shared without the need to add them explicitly in each feature module.

Project enables the TYPESAFE_PROJECT_ACCESSORS experimental Gradle feature to generate type safe accessors to refer other projects.

// Before
implementation(project(":feature_album"))

// After
implementation(projects.featureAlbum)

CI Pipeline

CI is utilizing GitHub Actions. Complete GitHub Actions config is located in the .github/workflows folder.

PR Verification

Series of workflows run (in parallel) for every opened PR and after merging PR to the main branch:

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

Design Decisions

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

Gradle Update

./gradlew wrapper --gradle-version=1.2.3

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 and project config.

Upcoming Improvements

Checklist of all upcoming enhancements .

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 and press Clone button

Command-line + Android Studio

  1. Run git clone https://github.com/igorwojda/android-showcase.git command to clone the project
  2. Open Android Studio and select File | Open... from the menu. Select cloned directory and press Open button

Inspiration

Here are few additional resources.

Cheatsheet

Android projects

Other high-quality projects will help you to find solutions that work for your project (random order):

  • Iosched - official Android application from google IO 2019
  • Android Architecture Blueprints v2 - a showcase of various Android architecture approaches
  • Now Android - fully functional Android app built entirely with Kotlin and Jetpack Compose
  • Android sunflower complete Jetpack sample 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 state approach together with very good documentation
  • Kotlin Android template - the template that lets you create preconfigured Android Kotlin project in a few seconds.
  • whatsApp-clone-compose - WhatsApp clone app built with Jetpack Compose and Stream Chat SDK for Compose
  • compose-samples - repository contains a set of individual Android Studio projects to help you learn about Compose in Android

Known issues

  • Dynamic feature module is not supported by ANDROID_TEST_USES_UNIFIED_TEST_PLATFORM yet.
  • ktlint FileName rule has to be disabled, becasue it is not compatible with fie containg a single extension ISSUE-1657
  • Delegate import is not provided when a variable has the same name as Delegate (KTIJ-17403)
  • Correct code is marked as an error in build.gradle.kts files when using libs from the Gradle Version Catalog (KTIJ-19370, KTIJ-19585)
  • ktlint import-ordering rule conflicts with IDE default formatting rule, so it have to be disabled. and KTIJ-16847)
  • False positive "Unused symbol" for a custom Android application class referenced in AndroidManifest.xml file (KT-27971)
  • Android lint complains about exceeding access rights to ArchTaskExecutor (Issue 79189568)
  • JUnit 5 does not support tests with suspended modifier (Issue 1914)

Contribute

Want to contribute? Check the Contributing docs.

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

About

πŸ’Ž Android application following best practices: Kotlin, Coroutines, JetPack, Clean Architecture, Feature Modules, Tests, MVVM, DI, Static Analysis...

License:MIT License


Languages

Language:Kotlin 100.0%