The Todo App

Google has published a Github repository for demoing Android development architecture, on a concrete app. The Todo app let you manage your todo list, in local or remote way (remote web service). The Google blueprints repository is available here and provides some declination of the app against architecture and technologies (MVP, MVVM, Dagger, Kotlin…).

I propose you to go with a “classical” MVP architecture, to compare Dagger and Koin approaches. Check the following repository for Todo App projects:

Dagger 2 version : https://github.com/googlesamples/android-architecture/tree/todo-mvp-dagger

Koin version: https://github.com/Ekito/android-architecture/tree/dev-todo-mvp-kotlin-koin

The Dagger project has been written by experts from the community. The Koin example project has been written by myself, inspired by the Google Kotlin version. Let’s go!

Overview

The application contains 4 self-describing packages, each one per view:

You can also find a data package for repository and datasources components. The di package is dedicated to dependency injection configuration. All of this is clearly identical in our two projects: you will find the same classes & packages in Dagger & Koin version.

We can clearly understand the application:

list all todo

add/edit a todo

view a todo

display statistics about todo

Google has opted for Activity/fragment per view: Activity is created, retrieve Fragment and Presenter. Fragment get the Presenter and Presenter need the TasksRepository.

Starting up

We won’t go through all views, but we will rather just take the TasksActivity workflow example to illustrate how each framework is working. Before anything, each framework needs some Gradle dependencies.

Dagger has been configured with a bunch of dependencies (and of course need a extra compiler plugin):

Dagger dependencies & plugin

Add Koin library with just one line:

Koin dependency

As regular Android framework, we must start each one in our Android Application class. Our Dagger version is based on DaggerApplication class. The class below also ensure dependency for TaskRepository into Application class (also needed for test purpose here).

Start Dagger with DaggerApplication

To start Koin, you just need to call ‘startKoin()’ function. No need for interface or any other special class. Also no need for special TaskRepository property injection.

The “todoAppModules” module just return a list of definitions, used in the application.

Declaring components

Now, to run the “Task list” view, we need to plug components like this:

In Dagger, all is annotation based and several module classes are needed to match different level of application context. The writing is consequently not straightforward, demanding us to write custom annotations (ActivityScope, FragmentScope).

Dagger’s module for Tasks context

We can simply do the same thing with Koin in a few lines. We just need to make one module (using applicationContext function), and use the Koin DSL to declare our components.

A Koin module describe all your components

Koin DSL is composed of only 5 keywords :

applicationContext — declare your Koin application context

— declare your Koin application context bean — declare a singleton instance component (unique instance)

— declare a singleton instance component (unique instance) factory — declare a factory instance component (new instance on each demand)

— declare a factory instance component (new instance on each demand) bind — declare an assignable class/interface to the provided component

— declare an assignable class/interface to the provided component get — retrieve a component, for provided definition function

The function provided by components can use the “get” function, to lazily resolve dependency needed for your component constructor.

Both Koin and Dagger do context management: drop instances that don’t need to survive to some life cycle (Fragment, Presenters …) and keep singleton components (Repository, Datasources).

Ready to inject

The Dagger app version is obviously based on annotations (@Inject, @ActivityScoped — previously created in your project). DaggerAppCompatActivity and DaggerFragment are support classes to help the plumbing. Lazyness is specified with custom Lazy type.

Activity, Fragment & Presenter with Dagger

Again, the same thing can be done very easily with Koin! 🙂 No need for annotation nor special class. To get your declared components with Koin, you can inject:

into Android classes with “inject()” function (TasksActivity, TasksFragment)

with function (TasksActivity, TasksFragment) into class constructors (TasksPresenter, TasksRepository)

Activity, Fragment & Presenter with Koin

Koin is that simple: resolve components with inject() function or direct by constructor

Note that the “inject()” function is lazy by nature and bind a with a Kotlin val property.

Koin don’t require any special Android classes nor any introspection. No need to write custom annotation to match your need.

Every time you modify your injection dependency configuration, no need to regenerate & recompile all stuff behind (no need of Dagger generation). All is an entire part of your application source code (any modification/refactoring is applied to your Koin module).

Dependency injection, the Koin way

All the Google TodoApp has been converted with Koin framework (check the Github repo). No proxy/CGLib, no code generation, no introspection. Just functional Kotlin and DSL magic 😉

Using Koin in your project doesn’t impact in terms of memory or cpu. Profiling with Android Studio the Dagger & Koin version gives the same performances aspect.

Koin brings simple but powerful features and helps you to stay focused on the essential.

Koin offers a simple way of writing your apps:

A DSL to simply describe your app with one or several modules

to simply describe your app with one or several modules Inject your instances via constructor or by “inject()” function

That’s it! No need to write anything else. All your app could be also described in one file — you to choose your modularity.

Scary about runtime dependency graph? Your Koin configuration can be checked with just a JUnit test and the dry run function.