Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Dependency injection with Dagger 2

Dependency injection with Dagger 2

Dagger 2.13 released with android support module and android compiler. I think this was a huge change for us and all android developers should switch to new dagger android injection as soon as possible.

Segnonna Hospice HOUNSOU

March 24, 2018
Tweet

More Decks by Segnonna Hospice HOUNSOU

Other Decks in Programming

Transcript

  1. • An application is made up of 2 or more

    classes • These classes collaborate each order to perform some operations WHAT IS DEPENDENCY INJECTION? PERSON EMAIL 3
  2. class Email { fun sendEmail(subject: String, message: String) { //

    Send the email } } TRADITIONAL WAY class Person { private val email = Email() fun greetFriend() { email.sendEmail("Hello", "Hello my friend :)") } } 5
  3. •The Person class is dependent (has strong dependency)on the Email

    class •Let say we update the Email’s constructor •Let decide to add different message delivery systems such as SMS , Tweets, …… •Testing the application will be very difficult SOME LIMITATIONS 6
  4. IMPLEMENT INTERFACES class EmailService : MessageService { override fun sendMessage(subject:

    String, message: String) { Log.e(EmailService::class.java.name, "Email: $subject, $message") } } class FastEmailService : MessageService { override fun sendMessage(subject: String, message: String) { Log.e(FastEmailService::class.java.name, "Fast Email: $subject, $message") } 9 class SmsService : MessageService { override fun sendMessage(subject: String, message: String) { Log.e(SmsService::class.java.name, "Sms: $subject, $message") } }
  5. class Person { private val email = Email() fun greetFriend()

    { email.sendEmail("Hello", "Hello my friend :)") } 10
  6. class Factory { val messageServiceDependency: MessageService get() = EmailService() }

    11 class Person { fun greetFriend(subject : String, message: String) { val mService = Factory().messageServiceDependency mService.sendMessage(subject,message) } } FACTORY WAY
  7. CONSTRUCTOR INJECTION class Person(private val messageService: MessageService){ override fun greetFriend(subject:

    String, message: String) { messageService.sendMessage(subject, message) } 12
  8. • Most Dependency Injectors Use
 ◦Reflexion For More Details
 ▪

    Is Very Slow And Time Consuming
 ▪ Perfom Dependencies Resolution At Runtime
 ▪ Leads Unexpected Errors
 ▪ Crashes The Application
 ◦Pre-Compiler
 ▪ Uses Android Processor
 ▪ Creates All Objects Using Ap
 DEPENDENCY INJECTION 14
  9. • Desing For Low-End Devices
 • Proposed By Java Libraries

    Core Team
 • Use Annotation Processing
 • Generate Modifies Classes Bases On Annotations
 • 100% Proguard Friendly
 • Generate Fully Traceable Code
 • Easy To Read Genereted Code
 • Performance
 WHY DAGGER 2? 15
  10. REAL-WORLD EXAMPLE 16 In Older versions, skype used Roboguice for

    injections As you can see, it takes 2415ms for injection when they used Roboguice.
  11. REAL-WORLD EXAMPLE 17 Over time, however, they switched to Dagger

    2, reducing injection time to a bare 170ms https://nimbledroid.com/
  12. • @Inject  :  Base Annotation Whereby The “Dependency Is Requested”


    • @Module  :  Classes Which Methods “Provide Dependencies”
 • @Provides :  Methods Inside @Module, Which “Tell Dagger How We Want To Build And Present A Dependency“
 • @Component  :  Bridge Between Modules And Injections
 • @Scope :  Enables To Create Global And Local Singletons • @Qualifier  :  If Different Objects Of The Same Type Are Necessary DAGGER 2 API? 18
  13. implementation « com.google.dagger:dagger:2. 13» kapt « com.google.dagger:dagger-compiler:2.123» compileOnly 'javax.annotation:jsr250-api:1.0' kapt

    "com.google.dagger:dagger-android-processor:2.13" implementation "com.google.dagger:dagger-android-support:2.13" 21
  14. Person.kt 22 interface PersonInterface { fun greetFriend(subject : String, message:

    String) } class Person @Inject constructor(private val messageService: MessageService) : PersonInterface { override fun greetFriend(subject: String, message: String) { messageService.sendMessage(subject, message) } }
  15. @Module class ApplicationModule(private var mApplication : MyApplication) { @Provides @Singleton

    fun provideMessageService(): MessageService { return SmsService() } @Provides @Singleton fun provideContext(): Context { return mApplication } @Provides @Singleton fun providePerson(person: Person): PersonInterface { return person } ApplicationModule.kt 23
  16. class MyApplication : Application() { companion object { lateinit var

    mApplicationComponent: ApplicationComponent } override fun onCreate() { super.onCreate() mApplicationComponent = DaggerApplicationComponent.builder() .applicationModule(ApplicationModule(this)) .build() mApplicationComponent.inject(this) } } MyApplication.kt 25
  17. class MainPresenter<V : MainActivityContrat.View> @Inject constructor(var person : PersonInterface) :

    BasePresenter<V>(), MainActivityContrat.Presenter<V> { override fun sendMessage(subject: String, message: String) { when{ TextUtils.isEmpty(subject) -> mMvpView.setSubjectError() TextUtils.isEmpty(message) -> mMvpView.setMessageError() else ->{ person.greetFriend(subject,message) mMvpView.showToast() } } MainPresenter.kt 26
  18. class MainActivity : AppCompatActivity() { @Inject lateinit var mPresenter: MainActivityContrat.Presenter<MainActivityContrat.View>

    override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) MyApplication.Companion.mApplicationComponent.inject(this) } MainActivity.kt 28
  19. @Module class ApplicationModule(private var mApplication : MyApplication) { @Provides @Singleton

    @ApplicationContext fun provideContext(): Context { return mApplication } } 30
  20. @Module class ActivityModule(private var mActivity : AppCompatActivity) { @Provides @Singleton

    @ActivityContext fun provideContext(): Context { return mActivity } @Provides fun provideMainPresenter(presenter: MainPresenter<MainActivityContrat.View>): MainActivityContrat.Presenter<MainActivityContrat.View> { return presenter } } 31
  21. CUSTUM ANNOTATION @Scope @kotlin.annotation.Retention(AnnotationRetention.RUNTIME) annotation class PerActivity @Scope @PerActivity @Component(dependencies

    = [(ApplicationComponent::class)], modules = [(ActivityModule::class)]) interface ActivityComponent { fun inject(mainActivity: MainActivity) } 32
  22. class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } } MainActivity.kt mActivityComponent = DaggerActivityComponent.builder() .activityModule(ActivityModule(this)) .applicationComponent(MyApplication.Companion.mApplicationComponent) .build() mActivityComponent.inject(this) 33
  23. • A class shouldn’t know anything about how it is

    injected. • Repeating ourselves in many places PRETTY SCARY, RIGHT? mActivityComponent = DaggerActivityComponent.builder() .activityModule(ActivityModule(this)) .applicationComponent(MyApplication.Companion.mApplicationComponent) .build() mActivityComponent.inject(this) 34
  24. @Module class ApplicationModule { @Provides @Singleton fun provideContext(mApplication : MyApplication):

    Context { return mApplication } @Provides @Singleton fun provideMessageService(): MessageService { return EmailService() } ApplicationModule.kt 36
  25. @Module abstract class MainActivityModule { @Binds abstract fun provideMainPresenter(presenter: MainPresenter<MainActivityContrat.View>):

    MainActivityContrat.Presenter<MainActivityContrat.View> } MainActivityModule.kt ActivityBuilder.kt @Module abstract class ActivityBuilder { @ContributesAndroidInjector(modules = [(MainActivityModule::class)]) abstract fun contributeMainActivity(): MainActivity } 37
  26. @Singleton @Component(modules = [AndroidInjectionModule::class, ApplicationModule::class, ActivityBuilder::class]) interface ApplicationComponent { @Component.Builder

    interface Builder { @BindsInstance fun application(application: Application): Builder fun build(): ApplicationComponent } fun inject(app: MyApplication) } ApplicationComponent.kt 38
  27. class MyApplication : DaggerApplication() { override fun applicationInjector(): AndroidInjector<out DaggerApplication>

    { val appComponent = DaggerApplicationComponent .builder() .application(this) .build() appComponent.inject(this) return appComponent } } MyApplication.kt 39
  28. class MainActivity : DaggerAppCompatActivity() { @Inject lateinit var mPresenter: MainActivityContrat.Presenter<MainActivityContrat.View>

    override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) mPresenter.onAttach(this) sendMessageButton.setOnClickListener { mPresenter.sendMessage(subject.text.toString(), message.text.toString()) } } MainActivity.kt 40
  29. DAGGER 2 DEPENDENCY GRAPH Install : npm install -g daggraph

    Usage : daggraph “gradleFolder” Select which chart you want to generate 42
  30. PROS OF DI WITH DAGGER 2 • REDUCE TO WRITE

    BOILER PLATE CODE
 • MAKE THE DEVELOPMENT PROCESS SMOOTH
 • EASILY TESTABLE CODE
 • CODE REUSABILITY
 • SIMPLE UNIT TESTING AND INTEGRATION TESTING
 • NO OBFUSCATION PROBLEMS
 • SMALL SIZE OF THE LIBRARY
 • 43
  31. WHERE TO LEARN DAGGER 2 •Dagger User’s Guide •Jake Wharton

    Talk •A Complete Guide To Learn Dagger 2 45 My code repo : https://bitbucket.org/pisso/daug-dagger-2
  32. 46