Over years Android architecture evolved to support production-quality apps on any scale focused on helping developers to design robust, testable, and maintainable apps. For that Google has promoted in the last years Kotlin as an official Android programming language impulse via a series of community-led events like Kotlin/Everywhere and programmers Udacity courses Kotlin Bootcamp. And it is not for less since the advantages are endless with respect to Java offering modern statically typed programming language that will boost your productivity and increase your developer happiness.
But first of all, if you want to check directly the project before continuing reading the introduction, you can do by accessing the following link:
https://github.com/VMadalin/kotlin-sample-app
The programming paradigm in android has seen a drastic turn with the introduction of Android Jetpack a suite of libraries, tools, and guidance to help developers write high-quality apps easier. These components help you to follow best practices, free you from writing boilerplate code, and simplify complex tasks. That has ended up giving rise to what is known today as Modern Android Development.
Android Architecture Components are part of Jetpack and are a collection of libraries that help you design robust, testable, and maintainable apps. Start with classes for managing your UI component lifecycle and handling data persistence.Â
Modular Android App Architecture presented from Yigit Boyar and Florina Muntenescu in Google I/O'19, is a software design technique to separate functionality into independent, interchangeable modules so that each contains everything necessary to execute a specific functionality.
The below diagram demonstrates how would an application that uses this software design technique, although if you want to see more, I recommend the following link.
Yet when it comes to combining all architecture puzzles together into simple client application it is difficult to find open-sourced app sample to follow. For this reason, I decided to build one based, apply and strictly complies with each of the following 5 points:
- A single-activity architecture, using the Navigation component to manage fragment operations.
- Android architecture components, part of Android Jetpack forgive to project a robust design, testable and maintainable.
- Pattern Model-View-ViewModel (MVVM) facilitating separation of development of the graphical user interface.
- S.O.L.I.D design principles intended to make software designs more understandable, flexible and maintainable.
- Modular app architecture allows being developed features in isolation, independently from other features.
The project presents a modern, 2019 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, modular application, 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 management.
Application structure
One of the key benefits of modularization architecture is supposed to be clear navigation throughout the app and source code. Looking at the root folder of the project, the following structure becomes clear:
Interaction between modules
Between the modules is established a dependency relationship that allows us to make an API request, access to DDBB or use a certain initialized library. Reusing the code in this way and avoiding duplicating. The below graph shows the app dependency between modules:
- :app depends on :core and indirectly depends on :features by dynamic-features.
- :features modules depend on :commons, :core, :app and some specific utils:library that will use.
- :core and :commons only depends on possible utils on :libraries.
- :libraries don't have any dependency.
App module
The :app module is a com.android.application, which is needed to create the App Bundle. It is also responsible for initiating the dependency graph, play core and other project global libraries, differentiating especially between different app environments.
Core module
The :core module is a com.android.library for serving network requests or accessing to the DDBB. Providing the data source for the many features that require it.
Features modules
The :features module are a com.android.dynamic-feature is essentially a gradle module which can be downloaded independently from the base application module. It can hold code and resources and include dependencies, just like any other gradle module.
Commons modules
The :commons modules are a com.android.library only contains code and resources which are shared between feature modules. Reusing this way layouts, views, and other components in the different features modules, without the need to duplicate code.
Libraries modules
The :libraries modules are a com.android.library, basically contains different utilities that can be used by the different modules.
Architecture components
Ideally, ViewModels shouldn't know anything about Android. This improves testability, leak safety and modularity. ViewModels have different scopes than activities or fragments. While a ViewModel is alive and running, an activity can be in any of its lifecycle states. Activities and fragments can be destroyed and created again while the ViewModel is unaware.
Passing a reference of the View (activity or fragment) to the ViewModel is a serious risk. Let's assume the ViewModel requests data from the network and the data comes back sometime later. At that moment, the View reference might be destroyed or might be an old activity that is no longer visible, generating a memory leak and, possibly, a crash.
The communication between the different layers follows the above diagram using the reactive paradigm, observing changes on components without the need of callbacks avoiding leaks and edge cases related to them.
Configuration files
With App Modularization we want to gain fine-grained dependency control but we also need to make sure we don't end up maintaining multiple configuration files.
For that we have the following common configuration files:
- commons/android-dynamic-feature.gradle.kts
- commons/android-library.gradle.kts
- commons/kotlin-library.gradle.kts
The following android-dynamic-feature.gradle.kts is applied to every feature module with the following line:
plugins {
id("commons.android-dynamic-feature")
}
Things to consider
Of course, nothing is perfect, especially if it has recently come out. Here are some issues what I found during development:
Navigation component doesn't support multiple back-stack for the moment. Exist different workarounds but not officially solution to this. (issue)
Robolectric isn't compatible with dynamic-features modules for the moment. Test on dynamic-feature throws the following exception. The same test but under android-library , works correctly. (issue)
java.lang.RuntimeException:java.lang.UnsupportedOperationException: libraries not supported yet
- Roboelectric throw the following exception on testing apps with data-binding in module. (issue)
java.lang.NoClassDefFoundError:androidx/databinding/DataBinderMapperImpl
- MockK with LiveData dependency throws an exception when trying to obtain value. (issue). The workaround is to use mockito for the moment. Â
java.lang.ClassCastException:java.lang.Object cannot be cast to java.lang.String
Additional Resources
Projects
This is project is a sample, to inspire you and should handle most of the common cases, but obviously not all. If you need to take a look at additional resources to find solutions for your project, visit these interesting projects:
- iosched (by google) - official Android application from google IO 2019.
- plaid (by android) - app which provides design news & inspiration, being an example of implementing material design.
- sunflower (by android) - a gardening app illustrating Android development best practices with Android Jetpack.
- architecture-components-samples (by android) - collection of samples for Android Architecture Components.
- architecture-sample (by android) - collection of samples to discuss and showcase different architectural tools and patterns for Android apps.
- android-clean-architecture-boilerplate (by bufferapp) - an android boilerplate project using clean architecture
- android-kotlin-clean-architecture (by sanogueralorenzo) - android sample Clean Architecture app written in Kotlin.
- modularization-example (by JeroenMols) - easy to understand real-life example of a modularized Android app.
- lego-catalog (by Eli-Fox) - app illustrating current Android Architecture state using Android development best practices.
- tivi (by chrisbanes) - an app which attempts to use the latest cutting edge libraries and tools.
- android-showcase (by igorwojda) - app following best practices: Kotlin, coroutines, Clean Architecture, feature modules, tests, MVVM, static analysis.
Articles
A collection of very interesting articles related last android community tendencies and recommendations for start to take in consideration for your current/next project:
- Transform monolith to modularization application
- Using the Navigation Component in a Modular World
- Dependency injection in a multi module project
- ViewModels and LiveData: Patterns + AntiPatterns
- Dynamic feature and regular modules using Dagger2
- Android Architecture starring Kotlin Coroutines, Jetpack (MVVM, Room, Paging), Retrofit and Dagger 2
- Official Kotlin Style Guide with Ktlint
- Gradle dependency management with Kotlin (buildSrc)
- Detecting Kotlin Code Smells with Detekt
- Best coding practices, tips and more for Android
Libraries
The open-source community create and maintains tons of awesome libraries making your job more easy, giving the opportunity to use them in your developments. Here are a very important collection of them:
- awesome-android-ui - collection list of awesome Android UI/UX libraries.
- awesome-android-libraries - collection of awesome Kotlin related stuff.
- android-arsenal - android developer portal with tools, libraries, and apps.
Best practices
Avoid reinventing the wheel by following these guidelines:
Codelabs
Google Developers Codelabs provide a guided, tutorial, hands-on coding experience. Most codelabs will step you through the process of building a small application, or adding a new feature to an existing application. They cover a wide range of android concepts to learn and practice:
Summary
There are certain benefits in writing or migrating to Modular App and using Architecture Components with them.Â
- Faster build times.
- Fine-grained dependency control.
- Improve reusability across other apps.
- Improves the ownership & the quality of the codebase.
- Stricter boundaries when compared to packages.
- Encourages Open Source of the newly created libraries.
- Makes Instant Apps & Dynamic Features possible (improving discoverability).
Remember, keeping modules Clean improves testability and eases future refactoring in case it needs to be shared between multiple user-facing features.
The aim of this article was to provide a brief overview of how to combining all architecture puzzles together into your current/next project.
If you have any questions, improvements, recommendations about modularization and architecture components please add your response 🙂.
The full open-source code can be found on GitHub:
https://github.com/VMadalin/kotlin-sample-app
Thanks for your time and reading.
V.Madalin
Top comments (0)