Clean Android Code: Preparation

Anton Averin
Axel Springer Tech
Published in
5 min readJun 7, 2016

Clean Android Code articles series:

  1. Clean Android Code: Main
  2. Clean Android Code: Building with Gradle
  3. Clean Android Code: Preparation
  4. Clean Android Code: Activities & Fragments
  5. Clean Android Code: Network & Data
  6. Clean Android Code: Navigation & UI
  7. Clean Android Code: Event Bus
  8. Clean Android Code: Error Handling
  9. Clean Android Code: ViewPager with View Pages
  10. Clean Android Code: Clean Adapter
  11. Clean Android Code: …

Before we start writing our first screen of the app, there are a few things we can setup beforehand. We can setup Dagger, agree on structure and prepare for testing.

Dagger 2

First let’s setup ApplicationContext and initialize dependency injection with Dagger 2.

I prefer a package view with flattened packages. Try it our, maybe you will like it too: in the Project window (⌘+1), click on a small arrow to the right of the list of (Packages | Scratches | … | Project Files| >), pick Project. Then click on a settings cog in the top-right corner of Project window and have Flatten Packages selected, Hide empty middle packages deselected

Let’s create a di package and put all DI-related classes there.

In Dagger setup I like to have 3 main scopes:

  • Singleton scope — things that are single in the whole applications. Classes of this scope are always attached to ApplicationContext
  • ActivityScope — something that is unique for every activity, such objects are attached to currently displaying activity and are re-created when new activity is being displayed
  • No scope — things that do not belong to any scope and are being re-created every time they are injected

Let’s call our ApplicationContext a BaseContext and keep rolling with DI.

AppComponent:

@Singleton
@Component(modules = arrayOf(
AppModule::class,
WebServicesModule::class,
SystemServicesModule::class
))
interface AppComponent {
//here we list things that are of Singleton-scope and should be accessible by other scopes
fun baseContext(): BaseContext
}

SystemServicesModule (as an example):

@Module
class SystemServicesModule(private val baseContext: BaseContext) {

@Provides
@Singleton
fun sharedPreferences(): SharedPreferences {
return PreferenceManager.getDefaultSharedPreferences(baseContext)
}
}

ActivityScope:

@Scope
@Retention
annotation class ActivityScope

ActivityComponent:

//make sure ActivityComponent is dependent on AppComponent
@ActivityScope
@Component(modules = arrayOf(ActivityModule::class), dependencies = arrayOf(AppComponent::class))
interface ActivityComponent {
//point where we manually inject dependencies into classes that we do not own a constructor of
//fun injectTo(mainActivity: MainActivity)
}

I usually call my Application class BaseContext, and all we need to do there at this moment is tie AppComponent to Application

appComponent = DaggerAppComponent.builder()
.appModule(AppModule(this))
.webServicesModule(WebServicesModule())
.systemServicesModule(SystemServicesModule(this))
.build()

Another place where we need to attach our injection scope is Activity, and to make sure that every Activity has a unique scope let’s make a BaseActivity class

/ui/common/view/BaseActivity

val baseContext = applicationContext as BaseContext activityComponent = DaggerActivityComponent.builder()
.appComponent(baseContext.appComponent)
.activityModule(ActivityModule(this))
.build();

As a result we have Singleton scope tied to BaseContext instance, ActivityScope tied to BaseActivity, meaning, to every displayed activity. And we have some sample dependencies available already for future reference.

All of the made changes can be found on Github feature branch

Project Modules

Another thing you would probably want to decide at this point is whether you want to have multiple modules in the project. You may want to do that to separate scopes of your classes, or to have a library code that you would like to share between different projects. It a good idea in general because Gradle (with org.gradle.parallel=true) will build modules in parallel, so it should be faster then putting everything into a single module

Rule of thumb is to separate layer of your application that is responsible for data access (network, database) into a separate module as android-library — if you ever decide to have a different UI implementation, your “backend” will be already available for you. It also helps separate concerns of different classes.

You could also have some library module dependency that only needs to be built for tests.

A few words about packaging. There 2 main approaches for packages structure in projects.

One is ‘do like Java’, so all Fragments will be in fragments, all Views will be view package, etc, and higher-level package only depends on lower-level package to avoid circular dependencies.

Another approach is to structure packages by scope, meaning, we will have ui package for all UI-related stuff, ui/common will be for generic things, and every screen will have it’s own package, like /ui/home/view, /ui/home/view/adapters and /ui/home/presenter. Such packages will have only things related to the particular screen, and if ever any class needs to be used on multiple screens — it needs to go higher in the hierarchy.

I have used both approaches in my practice and recently prefer the second one, because it easier to see code structure that way and packages are more compact.

So, in my sample project I separate ui and data layers with package structure, but that doesn’t mean that has to be the same for you. If you plan to make a large project I would recommend going with separate modules.

Helping your tests

Another thing we can prepare for is testing.

In Java, most of these things you will have our of the box — that is because testing libraries all come from Java initially. You would have some static imports, and test would look nice.

In Kotlin, things look a bit different. We have Kotlin classes in some places, there are some reserved words, like ‘if’, ‘for’ or ‘when’. A good thing — Kotlin is interoperable in Java, so once we add some Kotlin helper functions everything will look even better.

Some of the methods that I like adding are already available in Kotlin Hamcrest and Kotlin Mockito. So maybe you could look into those libraries instead of writing methods yourself.

I add following classes: MockitoKotlin, Hamcrest, CreateInstance, ArgThat. You can see full details on Github

The cool thing is that all the function in these classes are Kotlin Extension Functions, that can later be imported directly into the test and we will have clean and readable test code. I will show you this in the next part.

Next article in the series will be about Activities and Fragments — probably the most critical part in Android architecture. We will also do some testing.

Clean Android Code articles series:

  1. Clean Android Code: Main
  2. Clean Android Code: Building with Gradle
  3. Clean Android Code: Preparation
  4. Clean Android Code: Activities & Fragments
  5. Clean Android Code: Network & Data
  6. Clean Android Code: Navigation & UI
  7. Clean Android Code: Event Bus
  8. Clean Android Code: Error Handling
  9. Clean Android Code: ViewPager with View Pages
  10. Clean Android Code: Clean Adapter
  11. Clean Android Code: …

--

--