This article is the result of research, a byproduct of which was the embodiment of a long-standing idea in one very useful Android application, My Location Notifier , which was very short for me and was used to automatically notify the addressee of the user's arrival (see the detailed description here ).
So,
in the first part we built the main skeleton of the Android application in accordance with the MVP architecture. Now we will start to fasten to it Dagger 2.
2.1. Presetting
To begin with, go to the file build.gradle (Project: mymvcapp) and add the following line to the buildscript section:
')
ext.dagger2_version = "2.8"
At the time of this writing, this is the latest version of Dagger 2. Next, go to the file build.gradle (Module: app) and add the line to the beginning:
apply plugin: 'kotlin-kapt'
This is necessary so that in Dagger 2 it can generate its code when compiling. You will understand why later.
Now add the necessary dependencies:
implementation "com.google.dagger:dagger:$dagger2_version" kapt "com.google.dagger:dagger-compiler:$dagger2_version"
2.2. Preparation for injection
Synchronize the project and go back to the MainScreen component. Create a di.MainScreenModule class in the backstage package and annotate it with the
Module annotation. In the new class, we will declare and implement the providesPresenter () method: MainScreenPresenter = MainScreenPresenter and mark it with the
Provides and
Singleton annotations. So now our class will look like:
@Module class MainScreenModule { @Provides @Singleton fun providesPresenter(): MainScreenPresenter = MainScreenPresenter() }
Now let's move to the MainScreenCompatActivity class and replace the presenter's modifiers with lateinit var, remove the value assignment and mark it with the
Inject annotation:
class MainScreen : BaseCompatActivity(), MainScreenContract.View { @Inject lateinit var presenter: MainScreenPresenter override fun init(savedInstanceState: Bundle?) { setContentView(R.layout.activity_main_screen) presenter.attach(this) } }
Notice that the question mark is no longer needed when we access this variable.
It may seem that everything, the injection is made, the task is completed. And no. Now we need to force Dagger to generate the necessary code to implement our first dependency. That's why we added the kotlin-kapt plugin to the build script above. In the com.caesar84mx.mymvcapp package, we create the di.config package, in which we create the AppDiComponent interface.
Now, we will declare the interface as a component and singleton
and miserable , register our module in it, and declare the inject method (mainScreenActivity: MainScreen) inside the interface:
@Component( modules = [ MainScreenModule::class ] ) @Singleton interface AppDiComponent { fun inject(mainScreenActivity: MainScreen) }
And now, you must finally force Dagger to generate all the necessary code. To do this, we will create the MyMvpApp class in the config.di package, inherit it from the Application class, register the class in AndroidManifest.xml, and write the line android: name = ". Config.di.MyMvpApp" in the application tag. Next, we declare the variable lateinit var injector: AppDiComponent, set its private setter, override the onCreate () method. And start the magic:
class MyMvpApp: Application() { lateinit var injector: AppDiComponent private set override fun onCreate() { super.onCreate() injector = DaggerAppDiComponent.builder() .mainScreenModule(MainScreenModule()) .build() } }
As you have noticed, the DaggerAppDiComponent class does not exist yet, it will be generated when building the application. As well as the implementation of our component. The name of the class is made up of the word “Dagger” + the name of the interface marked as a component. The mainScreenModule () method will also be generated when building the project; the name must be composed of the class name of the injected module in lowerCamelCase.
Build the project (Build → Make Project). Enjoy automatic code generation and continue.
2.3. Injection
Attention: further, some dances with a tambourine with elements of porn will be presented. Please remove from the screen of children and nervous personalities.
We, for successful injections, will need a reference to the injector variable. Agree to create an instance of MyMvpApp in every class where we inject - not the best solution. Therefore, we will do the following:
class MyMvpApp: Application() { lateinit var injector: AppDiComponent private set override fun onCreate() { super.onCreate() INSTANCE = this injector = DaggerAppDiComponent.builder() .mainScreenModule(MainScreenModule()) .build() } companion object { private var INSTANCE: MyMvpApp? = null @JvmStatic fun get(): MyMvpApp = INSTANCE!! } }
Breathed out, returned to the MainScreen class. Now, in the init () method we inject our presenter. Do not forget that this action must be performed before the first reference to the injected variable. So now our class looks like:
class MainScreen : BaseCompatActivity(), MainScreenContract.View { @Inject lateinit var presenter: MainScreenPresenter override fun init(savedInstanceState: Bundle?) { setContentView(R.layout.activity_main_screen) MyMvpApp.get().injector.inject(this) presenter.attach(this) } }
And this is how the whole basic structure of our application looks like:
2.4. Conclusion
So, we have a minimal application structure ready, on which only it remains to hang the elements. Need a new activity? We represent it as a component, separate the ui from the backstage, for each component we determine which dependencies we need (at least, the presenter is active, and maybe, in the API presenter itself, to interact with the remote service, or, for example, the repository API for working with the database) prescribe the module with dependencies, register the module in the component, prescribe in the builder, rebuild the project, inject dependencies where necessary, repeat the iteration for each new component.
Of course, the question may arise: why do we need a Dagger? Were you doing great without him? Great, as long as the application is small. When it grows to full, with dozens of activities, fragments, adapters, server requests, data caching and other wonders, there will be a lot of dependencies that can be tracked in a large application rather than using Dependency Injection. Dagger's DI framework helps simplify the task of implementing and tracking them.