This project demonstrates Modern App Architecture best practices in a Multi-Module Android application using MVI architecture pattern. This app is made entirely in Kotlin and consumes pure Kotlin libraries to manage application data (SqlDelight, Ktor) and UI (Jetpack Compose). Dependency Injection is managed via Koin.
Dynamic Color enables users to personalize their devices to align tonally with the color scheme of their personal wallpaper or through a selected color in the wallpaper picker. You can read more about Dynamic Colors here.
dynamic-colors.mov
The app architecture has three layers: a data layer, a domain layer and a UI layer. The architecture follows a reactive programming model with unidirectional data flow. With the data layer at the bottom, the key concepts are:
- Higher layers react to changes in lower layers.
- Events flow down.
- Data flows up.
The data flow is achieved using streams, implemented using Kotlin Flows.
The UI layer is the pipeline that converts application data changes to a form that the UI can present and then displays it. The state is managed using a Unidirectional Data Flow (UDF) which aligns with the MVI (Model View Intent) architecture pattern's event-based nature.
While the UI layer contains UI-related state and UI logic, the data layer contains application data and business logic. The business logic is what gives value to your appβit's made of real-world business rules that determine how application data must be created, stored, and changed. The data layer is implemented as an offline-first source of app data and business logic. It is the source of truth for all data in the app.
The domain layer is an optional layer that sits between the UI layer and the data layer. The domain layer is responsible for encapsulating complex business logic, or simple business logic that is reused by multiple ViewModels. This layer contains Usecases/Interactors which interact with data sources inside Data Layer.
Rick & Morty App is an offline-first app and the app flow works as:
- Characters are fetched from Rick & Morty API using Ktor-client for Android.
- Characters are then stored in a SqlDelight Database. Our database inside Data layer is our single source of truth.
- The stored characters in cache are then requested by the Usecase in our domain layer.
- Characters from the cache are then exposed to the UI layer where they can be accessed as observable data streams i.e. Kotlin Flows.
This app has two screens:
- Characters List Screen
- Character Details Screen
We have following modules in our project. Among these modules, we have Android Application module, Android Library modules & pure Java/Kotlin Library modules. I have preferred using pure Kotlin libraries in domain & data layers as they can easily be reused in Kotlin Multiplatform projects. Therefore, SqlDelight is preferred over Room & Ktor client is used instead of Retrofit.
Module name | Type | Description |
---|---|---|
app | Android Application | Brings everything together required for the app to function correctly. This includes UI scaffolding and navigation. |
core | Java/Kotlin Library | Core business models and classes (such as DataState/Result wrapper classes) that are used by multiple modules. |
character-datasource | Java/Kotlin Library | Contains data-sources and private models such as CharacterDto & CharacterEntity (network and cache) for the characters module. |
character-domain | Java/Kotlin Library | Domain models and classes for the characters module i.e. data class Character |
character-interactors | Java/Kotlin Library | Use-cases for the characters Module. |
ui-character-list | Android Library | UI components for the CharactersList screen. |
ui-character-details | Android Library | UI components for the CharacterDetails screen. |
components | Android Library | Common Composables. |
- 100% Kotlin
- Coroutines - perform background operations
- Kotlin Flow - data flow across all app layers, including views
- Kotlin Symbol Processing - enable compiler plugins
- Kotlin Serialization - parse JSON
- Ktor client - Networking
- Jetpack
- Compose - modern, native UI kit
- Compose Navigation - in-app navigation
- SqlDelight - For local cache
- Koin - dependency injection (dependency retrieval)
- Coil - image loading library
- Modern Architecture
- MVI Architecture Pattern
- Android Architecture components (ViewModel, Kotlin Flows, Navigation)
- Android KTX - Jetpack Kotlin extensions
- UI
- Reactive UI
- Jetpack Compose - modern, native UI kit
- Material Design 3 - application design system providing UI components
- Theme selection
- Dark Theme - dark theme for the app (Android 10+)
- Dynamic Theming - use generated, wallpaper-based theme (Android 12+)
- Theme generated via Material Theme Builder
- Gradle dependencies are managed using the Version Catalog approach in
libs.versions.toml
file.
There are a few ways to open this project.
Android Studio
->File
->New
->From Version control
->Git
- Enter
https://github.com/shahzadansari/RickAndMorty.git
into URL field and pressClone
button
- Run
git clone https://github.com/shahzadansari/RickAndMorty.git
command to clone the project - Open
Android Studio
and selectFile | Open...
from the menu. Select the cloned directory and pressOpen
button
Add this repository to your watchlist to get notified about the latest updates in the repository.
- v1.4 Unit Tests
- v1.5 UI Tests
- v1.6 Pagination
All contributions are welcomed. This project is still in development. If you encounter any problems, please create an issue here & if you want to contribute to this project, PRs are welcomed! π
Shahzad Ansari