Tuesday, March 19, 2024
HomeAndroidBuilding a Multi Module App in Android | Modularization in Android #1

Building a Multi Module App in Android | Modularization in Android #1

-

Recently, I was in requirement for developing a Multi Module app in Android and I was going through this great lecture on it. This article is the summarization of the Android Multi Modular talk from Google IO 2019.

In this first article, we will briefly discuss about the approaches for Multi Modular app creation in Android. In the following article, we will look into the example app.

Advantages of a Multi Module app in Android

  1. Developers can work on certain sections of applications without slowing down other developers.
  2. Maintainability. All the files can be maintained in respective modules where it will be easier to find what we are looking out for.
  3. Incremental Compilation. If we modify a file, the modularised apps compile faster than the monolithic apps. Below screenshot shows the difference between the invalidation of files for monolithic app vs modularised app.monolithic vs modularized
  4. CI / CD will run faster. In the below example, If we use Incremental CI and If we made a Change in module 5, then the only tests CI pipeline can run are the tests present in Module 5 and the tests present in App Module because app module depends on all the modules.
  5. With App Bundles and Dynamic Delivery, we can significantly reduce apk size and therefore we can greatly experiment the different features which can take up large space.
Types of Modularisation

We will discuss about gradle library modules and dynamic feature modules here.

How we can Modularise?

We can modularise either by feature or either by layer. Let’s discuss about them in detail.

Modularisation by Features

Feature modularization consist of a base app – which is an android application and modules each with respective functionality – each extending android library. The app modules depend on these modules. Hence it implements those modules. Implementation of module in app gives the access to code and resources from that module to the app. Few Modules can be dynamic feature Modules.

Dynamic Feature Modules

Dynamic feature modules are the modules which can be used for on-demand code delivery which can be downloaded later. These modules will depend on the App module. We need to declare them in our app module’s build.gradle as dynamic feature modules.

The main restriction of feature modules in the app is – the app module cannot depend on dynamic feature modules. So in the above example, app module doesn’t depend on module 2 and module 3 as they are declared as dynamic modules.

App depends on Module 1 (Library Module). Hence in app’s build.gradle, we will add:


implementation project(':module1')

view raw

build.gradle

hosted with ❤ by GitHub

The other modules – module 2 and module 3 will implement app module as follows:


implementation project(':app')

view raw

gistfile1.txt

hosted with ❤ by GitHub

The app will declare them as dynamic feature modules as follows:


dynamicFeatures = [':module2', ':module3']

view raw

gistfile1.txt

hosted with ❤ by GitHub

Few dynamic features can be installed on-demand and few while downloading the app itself. These can be differentiated by using onDemand parameter.

If we enable the onDemand, we need to provide the module that can be downloaded via play store.

Core Module

Shared code and resources will be the part of core module.

The best feature of on-demand is that if there are third party libraries which the on-demand module requires, we can download them later saving the lot of space that requires the third party app to download.

Related Links

Getting started with RXJava

How to decide what feature can be declared as dynamic module?

Mostly users uses 20% of our app. We can deliver the features such as Paid features, features which require space but can not used frequently at a later point of time. Often small features can be placed in library as they are small and user shouldn’t wait for long for them to download dynamically.

Eg: Search and About features can be library modules.

Layer Modularization

The following image is the example of Layer Modularization where we are declaring different layers color coded into different modules.

API vs Implementation

Suppose Module A has API dependence on Module B, it means all the public functionality by Module B is accessible by Module A where as when A has Implementation dependence on B, modules that depend on A cannot access B’s functionality.

Advantage of this kind of modularisation is testing. We can easily create fake implementation for repositories where the team member working on the repositories layer knows exactly how the data needs to be mocked.

Feature modularisation vs layer modularization

Feature modularisation brings in the encapsulation and possibility of on-demand delivery.

Layer modularisation brings in isolation and structure to our app.

Challenges and solutions to work with Dynamic Feature Modules (DFM)

There are few challenges involved inside dynamic feature modules. Let us discuss about them.

Navigation

Let us think our about feature is inside DFM and we are in our app’s main activity. Now we want to launch the AboutActivity present in DFM where we do not have access to it. To overcome this we need to declare and pass the component name as follows:

multi module app in android - snippet showing how an activity is called from another module

If we are using fragment then we need to add it to proguard exclusions also for it to work properly. For fragments, here is the code snippet:

multi module app in android - snippet showing how a fragment is called from another module

While these are harcoded strings are not a good solution, google team promises to fix them in the next releases.

Communicate between modules

Let us take a scenario to properly analyse the problem between moSuppose we need to search from two different modules – stories and users. Suppose search is a different module. We need to use search module to perform search on posts and users module. The way we do is to create an interface in core module – DataSource, which these two modules depend on, and implementing the interface in both modules. This gives two classes – StoriesDataSource and UsersDataSource – both implementing DataSource interface.

But to instantiate these data sources, we need to instantiate the following too:

multi module app in android - dependencies

The above classes such as service, sharedpreferences, etc. needs to be instantiated for the data sources to be instantiated.

In core, we will create a DataSourceProvider interface that will contain getDataSource() function.


interface DataSourceProvider {
fun getDataSource(context:Context):DataSource
}

Then we will create StoriesDataSourceProvider that will implement DataSourceProvider.


class StoriesDataSourceProvider : DataSourceProvider {
override fun getDataSource(context:Context) : DataSource {
//build dependencies
return datasource
}
}

In search, we will provide the set of all data sources. We will check if feature is installed. If it is, we will create the new instance using reflection or service loader as DataSourceProvider as shown in the image below:

multi module app in android - data sources declaration in search module

In the above example, if we use service loader, the provider will be like:


val providers = ServiceLoader.load(DataSourceProvider::class.java, null)
val dataSources = providers.map {
it.getDataSource(activity)
}.toSet()

Here is the link to google samples to checkout both of the above versions:

https://github.com/googlesamples/android-dynamic-code-loading

DataSources using Dagger

If we are using Dagger, we will be using component – CoreComponent which we created in core module.

This good when dynamic modules are already installed. If they aren’t installed, we will use LiveData<Set<DataSource>>.

We can register listeners to react to installation of new modules.

Working with Databases in Multi module app in Android

When we modularise an app, we face problem about where to keep our database. While there is no specific correct method to do so, one of the implementation is using a single common database for the entire app. The other is creating a database for core common functionality and then separate for feature modules.

Pros / cons of a Single Database
Pros:
  1. Easy to maintain database connection since we need to open one db connection only.
  2. Easy to share tables.
Cons:
  1. No isolation between modules therefore we need to rename these tables to not conflict across modules.
  2. No specific entities are in shared domain. We need to put all entities and daos into core module that ships with app.
Pros / cons of a One Database / Module
Pros:
  1. Perfect isolation between modules
Cons:
  1. DB connection maintanence. If we want to write a queries across modules, it is complex.

The google devs promise the multi modular aproach support using Room database, but in future.

Reference:

In the next tutorial, we will be creating a Multi module App in Android.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

This site uses Akismet to reduce spam. Learn how your comment data is processed.

LATEST POSTS

Packages in Java

Hello World! Today's blog is about packages in java. Here, we will learn about what are packages and how we can use packages along with...

SOLID Principles in Android with Kotlin Examples

Recently I had an interview experience where I went blank when the interviewer posed an Interesting Question - Explain SOLID Principles and how they are...

Python Lambda Function with Examples

In this article, we will discuss briefly about Python Lambda function along with an example. A Lambda function is an anonymous function which takes arguments and...

Lambda function in Kotlin with Examples

Lambda function is powerful feature in any Programming language and Lambda function in Kotlin is no exception. In this article, we will look at how...

Follow us

1,358FansLike
10FollowersFollow
399SubscribersSubscribe

Most Popular