Android DTT #22 — Split Code Into Modules
--
When you’re at the beginning of apps development. You create a few pages with few data. Then you see it compiles quickly. Not even 20 seconds needed.
You continue to build the apps. More activities, more fragments. One year passed, two year passed. You hit the 65k method limit. Going on and on adding features. Then eventually you’ll reach the build time of 3 minutes with a pretty decent laptop.
There are many reasons on why the build time is taking so long. The reason that happens to my team is that we use annotation processor library such as DataBinding, Dart&Henson, ButterKnife, Dagger2 etc. And with code that use annotation processor, the java incremental build won’t work.
That means when you modify code in one file of your project, the whole project get recompiled.
We can get around this by splitting the code into modules. When you change the code in a module. Only modules that depends on it will get recompiled.
You can see the more detailed explanation by the CEO of Gradle:
How to structure the module?
I’d suggest that you split the code into modules by feature first, not by layer. So for an e-commerce app you’d probably have: app
, core
, checkout
, user
, and search
.
Those modules should not depends one and another directly. You can bridge the connection using another module that contains only the interface and data structure.
Let’s do an example. When user done searching the product (in search
module) the user then will click a button that will lead them to the checkout page (in checkout
module). Instead of making search
module depends on checkout
module to call the activity directly, we can create a checkout-public
module which contains only an interface:
// inside checkout-publicpublic interface CheckoutService {
void goToCheckout(SelectedGoods selectedGoods);
}
Both checkout
and search
module will depends on the checkout-public
. The implementation of CheckoutService
will reside in checkout
:
// code inside checkout modulepublic class CheckoutServiceImpl implements CheckoutService {
@Override
public void goToCheckout(SelectedGoods selectedGoods) {
// goto activity, call API, etc
}
}
Then you can call the service in search
module:
// code inside search module// Use DI such as dagger. Construct the dependency graph in the top // level module (app)
@Inject
private CheckoutService checkoutService;
public void onCheckoutButtonClick() {
checkoutService.goToCheckout(getSelectedGoods());
}
This way, the search
module did not need to know on how the checkout page will be rendered since it’s not his business anymore. And when you modify the search
module, when you compile the code again the checkout
module won’t be compiled again.
I’d suggest that you should start doing this from the beginning since doing it midway will takes more times to refactor all the things that are tightly coupled.
For small projects, the overhead of creating the structure may not worth it, but for big projects it definitely is.
If you like this, hit that heart button and recommend it to your friends.
ADTT (Android Development Tips and Tricks) is a 31 series of blog posts that I’m trying to finish in throughout May. Click here for index.