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

Hilt the DI ground running

Hilt the DI ground running

This talk was about Dependency Injection with Hilt at DevFest Egypt. First I explained the concept of Dependency Injection without libraries. Next, I showed how to incorporate Hilt into a new app and how to migrate an existing app.

E803718649600ddffc1bc625d957e786?s=128

Moyinoluwa Adeyemi

October 17, 2020
Tweet

Transcript

  1. Hilt the DI ground running Moyinoluwa Adeyemi @moyheen

  2. What is Dependency Injection?

  3. What is Dependency Injection? “dependency injection is a technique in

    which an object receives other objects that it depends on” According to good ol’ wikipedia
  4. Dependency Injection

  5. Dependency Injection

  6. No Dependency Injection class RoboGardener { fun waterPlant() { val

    waterSource = WaterSource() waterSource.dispenseWater() } }
  7. Dependency Injection - Constructor class RoboGardener(private val waterSource: WaterSource) {

    fun waterPlant() { waterSource.dispenseWater() } }
  8. Dependency Injection - Constructor class RoboGardener(private val waterSource: WaterSource) {

    fun waterPlant() { waterSource.dispenseWater() } } fun main() { val roboGardener = RoboGardener(CupOfWater()) roboGardener.waterPlant() }
  9. Dependency Injection - Setter class RoboGardener { lateinit var waterSource:

    WaterSource fun waterPlant() { waterSource.dispenseWater() } }
  10. Dependency Injection - Setter class RoboGardener { lateinit var waterSource:

    WaterSource fun waterPlant() { waterSource.dispenseWater() } } fun main() { val roboGardener = RoboGardener() roboGardener.waterSource = WateringCan() roboGardener.waterPlant() }
  11. Dependency Injection - Interface interface WaterSourceManager { fun provideWaterSource(waterSource: WaterSource)

    }
  12. Dependency Injection - Interface interface WaterSourceManager { fun provideWaterSource(waterSource: WaterSource)

    } class RoboGardener() : WaterSourceManager { private lateinit var waterSource: WaterSource override fun provideWaterSource(waterSource: WaterSource) { this.waterSource = waterSource } ...
  13. Dependency Injection - Interface interface WaterSourceManager { fun provideWaterSource(waterSource: WaterSource)

    } class RoboGardener() : WaterSourceManager { private lateinit var waterSource: WaterSource override fun provideWaterSource(waterSource: WaterSource) { this.waterSource = waterSource } fun waterPlant() { waterSource.dispenseWater() } } fun main() { val roboGardener = RoboGardener() roboGardener.provideWaterSource(Hose()) roboGardener.waterPlant() }
  14. RoboGardener WaterSource Dependency Injection - Graph

  15. Service Locators

  16. Service Locators class RoboGardener { fun waterPlant() { val waterSource

    = CupOfWater() waterSource.dispenseWater() } }
  17. class RoboGardener { fun waterPlant() { val waterSource = ServiceLocator.getInstance.findWaterSource()

    waterSource.dispenseWater() } } Service Locators
  18. No increase in app size Manual Dependency Injection

  19. Manual Dependency Injection No increase in app size Low Learning

    Curve
  20. High maintenance costs Manual Dependency Injection Low Learning Curve No

    increase in app size ♀
  21. Dependency Injection - Dagger Dagger Code generation Steep learning curve

    For Java or Kotlin developers Useful for large projects
  22. Dependency Injection - Hilt What is different?

  23. Dependency Injection - Hilt Low Learning Curve

  24. Dependency Injection - Hilt Low Learning Curve Free Lifecycle Management

  25. Dependency Injection - Hilt Low Learning Curve Free Lifecycle Management

    ♻ Co-exist with Dagger ♂
  26. Dependency Injection - Hilt Usage - Annotations

  27. @HiltAndroidApp class HiltSampleApplication : Application() @HiltAndroidApp

  28. @AndroidEntryPoint class MainActivity : AppCompatActivity() { @Inject lateinit var imageLoader:

    ImageLoader private val viewModel: HiltSampleViewModel by viewModels() ... @AndroidEntryPoint
  29. Activity imageLoader viewModel @AndroidEntryPoint

  30. @Module @InstallIn(ApplicationComponent::class) abstract class AppModule @InstallIn

  31. @Module @InstallIn(ApplicationComponent::class) abstract class AppModule { @Binds abstract fun bindImageLoader(imageLoader:

    GlideImageLoader): ImageLoader ... } @InstallIn
  32. @Module @InstallIn(ApplicationComponent::class) object NetworkModule { @Provides fun providesMoshi(): Moshi =

    Moshi.Builder() .build() ... @InstallIn
  33. class HiltSampleViewModel @ViewModelInject constructor( private val hiltSampleRepository: HiltSampleRepository ) :

    ViewModel() { ... ViewModels - @ViewModelInject
  34. ViewModel repository ViewModels - @ViewModelInject Activity imageLoader viewModel

  35. @AndroidEntryPoint @AndroidEntryPoint class MainActivity : AppCompatActivity() { @Inject lateinit var

    imageLoader: ImageLoader private val viewModel: HiltSampleViewModel by viewModels() ...
  36. @EntryPoint - Interface @EntryPoint @InstallIn(ApplicationComponent::class) interface ImageFeatureModule { fun imageLoader():

    ImageLoader }
  37. @EntryPoint - Dependency retrieval val imageLoader = EntryPoints .get(applicationContext, ImageFeatureModule::class.java)

    .imageLoader()
  38. @EntryPoint - Interface retrieval EntryPointAccessors.fromApplication( applicationContext, ImageFeatureModule::class.java )

  39. Dependency Injection - Hilt Usage - Scoping

  40. https://developer.android.com/training/dependency-injection/hilt-android#component-scopes Scoping

  41. https://dagger.dev/hilt/component-hierarchy.svg Scoping - Hierarchy

  42. Scoping - Unscoped bindings @Module @InstallIn(ApplicationComponent::class) abstract class AppModule {

    @Binds abstract fun bindImageLoader(imageLoader: GlideImageLoader): ImageLoader ...
  43. Scoping - Scoped bindings @Module @InstallIn(ApplicationComponent::class) abstract class AppModule {

    @Singleton @Binds abstract fun bindImageLoader(imageLoader: GlideImageLoader): ImageLoader ... ✅
  44. Scoping - Scoped bindings @Module @InstallIn(ApplicationComponent::class) abstract class AppModule {

    @ActivityRetainedScoped @Binds abstract fun bindImageLoader(imageLoader: GlideImageLoader): ImageLoader ... ❌
  45. Scoping - Scoped bindings

  46. class HiltSampleViewModel @ViewModelInject constructor( private val hiltSampleRepository: HiltSampleRepository ) :

    ViewModel() { ... ActivityRetainedComponent Scoping - ViewModel bindings
  47. Scoping - Predefined qualifiers @ActivityContext - Activity Context binding @ApplicationContext

    - Application Context binding
  48. Scoping - Predefined qualifiers class HiltSampleRepositoryImpl @Inject constructor( @ActivityContext private

    val context: Context, private val hiltSampleService: HiltSampleService ) : HiltSampleRepository {
  49. Scoping - Recommendation “only scope the binding if it’s required

    for the correctness of the code”
  50. Dependency Injection - Hilt Usage - Multi-module apps

  51. Multi-module apps - Gradle modules Regular gradle modules? ✅

  52. Multi-module apps - Feature modules Feature Modules?

  53. Multi-module apps - Feature modules “Hilt cannot process annotations in

    feature modules. You must use Dagger to perform dependency injection in your feature modules” Hilt + Dagger
  54. Multi-module apps - Feature modules 1. Install an Entry Point

    in the Application Component from the app module
  55. Multi-module apps - Feature modules 1. Install an Entry Point

    in the Application Component from the app module @EntryPoint @InstallIn(ApplicationComponent::class) interface ImageFeatureModule { fun imageLoader(): ImageLoader }
  56. Multi-module apps - Feature modules 2. In the feature module,

    create a regular dagger component
  57. Multi-module apps - Feature modules 2. In the feature module,

    create a regular dagger component @Component(dependencies = [ImageFeatureModule::class]) interface ImageFeatureComponent { fun inject(activity: ImageFeatureModuleActivity) @Component.Builder interface Builder { fun dependencies(imageFeatureModule: ImageFeatureModule): Builder fun build(): ImageFeatureComponent } }
  58. Multi-module apps - Feature modules 3. Inject the dependency in

    the feature module
  59. Multi-module apps - Feature modules 3. Inject the dependency in

    the feature module class ImageFeatureModuleActivity : AppCompatActivity() { @Inject lateinit var imageLoader: ImageLoader @AndroidEntryPoint
  60. Multi-module apps - Feature modules 3. Inject the dependency in

    the feature module ... override fun onCreate(savedInstanceState: Bundle?) { DaggerImageFeatureComponent.builder() .dependencies( EntryPointAccessors.fromApplication( applicationContext, ImageFeatureModule::class.java ) ) .build() .inject(this)
  61. Multi-module apps - Feature modules 3. Inject the dependency in

    the feature module ... override fun onCreate(savedInstanceState: Bundle?) { DaggerImageFeatureComponent.builder() .dependencies( EntryPointAccessors.fromApplication( applicationContext, ImageFeatureModule::class.java ) ) .build() .inject(this)
  62. Dependency Injection - Migration Dagger Android -> Hilt

  63. Migration - build.gradle

  64. Migration - app/build.gradle

  65. Migration - app/build.gradle

  66. Migration - Application

  67. Migration - Hilt_HiltSampleApplication.java (generated)

  68. Migration - ViewModel

  69. Migration - HiltSampleViewModel_AssistedFactory.java (generated)

  70. Migration - HiltSampleViewModel_HiltModule.java (generated)

  71. Migration - MainActivity

  72. Migration - Hilt_MainActivity.java (generated)

  73. Migration - Hilt_MainActivity.java (generated)

  74. Migration - Modules

  75. Migration - ViewModelFactory, ViewModelKey

  76. Migration - HiltSampleApplication_HiltComponents.java (generated)

  77. Resources • Dependency injection with Hilt • Dagger Hilt •

    Using Hilt in your Android app Codelab • Migrating your Dagger app to Hilt Codelab • Scoping in Android and Hilt. Scoping an object A to another object B… | by Manuel Vivo | Android Developers • Hilt in multi-module apps • https://github.com/moyheen/HiltSampleApplication • Image by Gerd Altmann from Pixabay
  78. Thank You! Moyinoluwa Adeyemi @moyheen