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

의존성 주입과 Dagger Hilt

의존성 주입과 Dagger Hilt

2024년 5월 22일 (수) 삼성전자에서의 발표자료입니다.

Sungyong An

May 22, 2024
Tweet

More Decks by Sungyong An

Other Decks in Programming

Transcript

  1. class Car { private val engine: Engine = Engine() //

    construct + use fun start() { engine.start() } } fun main(args: Array) { val car = Car() car.start() } Car Engine Current
  2. class Car( private val engine: Engine // use ) {

    fun start() { engine.start() } } fun main(args: Array) { val engine = Engine() // construct val car = Car(engine) car.start() } Car With DI (Constructor Injection) Engine
  3. class Car { lateinit var engine: Engine // use fun

    start() { engine.start() } } fun main(args: Array) { val car = Car() car.engine = Engine() // construct car.start() } With DI (Field Injection) Car Engine
  4. Engine , Car . fun main(args: Array<String>) { val electricCar

    = Car(ElectricEngine()) val combustionCar = Car(CombustionEngine()) ... } Reuse Car
  5. class CarTest { @Test fun `Car happy path`() { val

    car = Car(FakeEngine()) ... } @Test fun `Car with failing Engine`() { val car = Car(FakeFailingEngine()) ... } } Ease of Testing
  6. class Car { private val engine: Engine = Engine() }

    fun main(args: Array) { val car = Car() car.start() } Car Engine Current
  7. class Car( private val engine: Engine ) { ... }

    fun main(args: Array) { val engine = Engine() val car = Car(engine) car.start() } Car Dependency Injection Engine
  8. class Car { private val engine: Engine = ServiceLocator.get() }

    object ServiceLocator { fun getEngine() : Engine = Engine() } fun main(args: Array) { val car = Car() car.start() } Service Locator Engine Car Service Locator
  9. ? . Android Studio Dagger/Hilt . DI . DI ,

    . Link: h tt ps://medium.com/androiddevelopers/dagger-navigation-suppo rt -in-android-studio-49aa5d149ec9
  10. class ExampleViewModel( private val database: Database, private val network: Network,

    ) : ViewModel() { fun doSomething() { database.getSomething().subscribe(...) network.getSomething().subscribe(...) } } class Database { ... } class Network { ... } Manual DI
  11. class ExampleActivity: Activity() { private lateinit var viewModel: ExampleViewModel override

    fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val database = Database() // Singleton੉ ইפ׮. val network = Network() // ૊, ݒߣ ࢤࢿػ׮. viewModel = ExampleViewModel(database, network) viewModel.doSomething() } } Manual DI
  12. class ExampleActivity: Activity() { private lateinit var viewModel: ExampleViewModel override

    fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val database = Database() // Singleton੉ ইפ׮. val network = Network() // ૊, ݒߣ ࢤࢿػ׮. viewModel = ExampleViewModel(database, network) viewModel.doSomething() } } Manual DI
  13. class AppContainer { val database = Database() val network =

    Network() } class MyApplication : Application() { val appContainer = AppContainer() }
  14. class ExampleActivity: Activity() { private lateinit var viewModel: ExampleViewModel override

    fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val appContainer = (application as MyApplication).appContainer viewModel = ExampleViewModel(appContainer.database, appContainer.network) viewModel.doSomething() } }
  15. class AppContainer { private val database = Database() private val

    network = Network() private val localDataSource = ExampleLocalDataSource(database) private val remoteDataSource = ExampleRemoteDataSource(network) val exampleRepository = ExampleRepository(localDataSource, remoteDataSource) } class MyApplication : Application() { val appContainer = AppContainer() }
  16. class ExampleActivity: Activity() { private lateinit var viewModel: ExampleViewModel override

    fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val appContainer = (application as MyApplication).appContainer viewModel = ExampleViewModel(appContainer.exampleRepository) viewModel.doSomething() } }
  17. // জࠁ׮ ੘਷ ߧਤ੄ ੄ઓࢿ ஶప੉ց class ExampleContainer(val exampleRepository: ExampleRepository)

    { val exampleData = ExampleData() val exampleViewModelFactory = ExampleViewModelFactory(exampleRepository) } class AppContainer { ... val exampleRepository = ExampleRepository(localDataSource, remoteDataSource) var exampleContainer: ExampleContainer? = null } : Custom Scope
  18. class ExampleActivity: Activity() { private lateinit var viewModel: ExampleViewModel private

    lateinit var appContainer: AppContainer private lateinit var data: ExampleData override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) appContainer = (application as MyApplication).appContainer appContainer.exampleContainer = // ੄ઓࢿ ஶప੉ց ࢤࢿ ExampleContainer(appContainer.exampleRepository) viewModel = appContainer.exampleContainer.exampleViewModelFactory.create() data = appContainer.exampleContainer.exampleData } ... : Custom Scope
  19. class ExampleActivity: Activity() { private lateinit var viewModel: ExampleViewModel private

    lateinit var appContainer: AppContainer private lateinit var data: ExampleData ... override fun onDestroy() { appContainer.exampleContainer = null // ੄ઓࢿ ஶప੉ց ࢏ઁ super.onDestroy() } } } : Custom Scope
  20. DI . Android ߂ Java ਊ ੄ઓࢿ ઱ੑ ೐ۨ੐ਕ௼. ஹ౵ੌ

    ఋ੐ী ࣗझ௏٘ ࢤࢿ. Dependency Injection ಁఢ. https://github.com/google/dagger Dagger ӝ߈ Android ੄ઓࢿ ઱ੑ ೐ۨ੐ਕ௼. ؀ࠗ࠙੄ Dagger ࢚ਊҳ ઁѢ. Dependency Injection ಁఢ. https://github.com/google/dagger Dagger Hilt (Recommended) Dagger੄ ੄ઓࢿ ઱ੑਸ ؊ औѱ ݅٘ח Kotlin ஹ౵ੌ۞ ೒۞Ӓੋ. Dependency Injection ಁఢ. https://github.com/square/anvil Anvil Kotlin ҃۝ ੄ઓࢿ ઱ੑ ೐ۨ੐ਕ௼. ۠ఋ੐ী ੄ઓࢿ Ӓې೐ ҳࢿ. Service Locator ಁఢ. https://github.com/InsertKoinIO/koin Kotlin ਊ ੄ઓࢿ ઱ੑ ۄ੉࠳۞ܻ. ஹ౵ੌ ఋ੐ী ੄ઓࢿ Ӓې೐ ਬബࢿ Ѩࢎ. KSP, Kotlin Multiplatform ૑ਗ. https://github.com/evant/kotlin-inject Koin kotlin-inject …
  21. Dagger Hilt Android . Android , . (Application, Activity, Service,

    BroadcastReceiver, ViewModel) Dagger , . Jetpack Hilt .
  22. @Module @InstallIn(SingletonComponent::class) class EngineModule { @Provides // construct fun providesEngine():

    Engine = Engine() } Engine @Provides ١ਸ ੉ਊೞৈ, ੄ઓࢿਸ ઁҕೡ ࣻ ੓׮.
  23. @Module @InstallIn(SingletonComponent::class) class EngineModule { @Provides // construct fun providesEngine():

    Engine = Engine() } // Dependency Injection (Constructor Injection) class Car @Inject constructor( // use private val engine: Engine, ) Car Engine @Injectܳ ੉ਊೞৈ, ੄ઓࢿਸ ௿ېझ ࢤࢿ੗ী ઱ੑೡ ࣻ ੓׮.
  24. @Module @InstallIn(SingletonComponent::class) class EngineModule { @Provides fun providesEngine(): Engine =

    Engine() } // Dependency Injection (Constructor Injection) class Car @Inject constructor( // construct private val engine: Engine, ) @AndroidEntryPoint class ExampleActivity : ComponentActivity() { // Dependency Injection (Field Injection) @Inject // use lateinit var car: Car } Car ExampleActivity Engine Android ௿ېझח ࢤࢿ੗о ইצ, ೙٘ী ੄ઓࢿਸ ઱ੑೠ׮.
  25. @Module @InstallIn(SingletonComponent::class) class EngineModule { @Provides fun providesEngine(): Engine =

    Engine() } // Dependency Injection (Constructor Injection) class Car @Inject constructor( private val engine: Engine, ) @AndroidEntryPoint class ExampleActivity : ComponentActivity() { // Dependency Injection (Field Injection) @Inject lateinit var car: Car } = public @interface Module { ... } = public @interface InstallIn { ... } = public @interface Provides {} = public @interface Inject {} = public @interface AndroidEntryPoint { ... } = public @interface Inject {} Annotationਸ ӝ߈ਵ۽, ੄ઓࢿਸ ઱ੑೞח ௏٘ܳ ࢤࢿ೧ળ׮.
  26. // project’s root build.gradle buildscript { repositories { mavenCentral() }

    dependencies { classpath 'com.google.dagger:hilt-android-gradle-plugin:2.48' } } // module’s build.gradle apply plugin: 'com.google.dagger.hilt.android' Gradle Build Setup
  27. // module’s build.gradle dependencies { implementation 'com.google.dagger:hilt-android:2.48' // For Java

    annotationProcessor 'com.google.dagger:hilt-compiler:2.48' // For Kotlin kapt 'com.google.dagger:hilt-compiler:2.48' // or ksp 'com.google.dagger:hilt-compiler:2.48' } Gradle Build Setup
  28. Hilt Basics Dagger Hilt . @HiltAndroidApp @AndroidEntryPoint, @EntryPoint Components SingletonComponent,

    ViewModelComponent, ActivityComponent, ... Scopes @Singleton, @ViewModelScoped, @ActivityScoped, … Modules @Inject, @Module, @Provides, @Binds, @Quali fi er, …
  29. Hilt Application Hilt Application @HiltAndroidApp . , Hilt . @Inject

    , . @HiltAndroidApp class MyApplication : Application() { @Inject lateinit var data: ExampleData } MyApplication ExampleData
  30. Android Android @AndroidEntryPoint . @Inject , . @AndroidEntryPoint class ExampleActivity

    : ComponentActivity() { @Inject lateinit var data: ExampleData } ... ExampleActivity ExampleData
  31. @AndroidEntryPoint class ExampleFragment : Fragment() { ... } @AndroidEntryPoint class

    ExampleView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, ) : View(context, attrs, defStyleAttr) { ... } @AndroidEntryPoint class ExampleService : Service() { ... } @AndroidEntryPoint class ExampleBroadcastReceiver : BroadcastReceiver() { ... }
  32. @AndroidEntryPoint // X class ExampleContentProvider : ContentProvider() { ... }

    // Activity, Fragment, View, Service, BroadcastReceiverо ইצ, // ׮ܲ Android ௿ېझীח @AndroidEntryPointܳ ࢎਊೡ ࣻ হ׮.
  33. Hilt @EntryPoint . Context Hilt . Hilt @EntryPoint @InstallIn(SingletonComponent::class) interface

    ExampleEntryPoint { fun foo(): Foo } val entryPoint = EntryPointAccessors.fromApplication( appContext, // Context ExampleEntryPoint::class.java, ) val foo = entryPoint.foo()
  34. val entryPoint = EntryPointAccessors.fromActivity( activity, // Activity ExampleEntryPoint::class.java, ) val

    entryPoint = EntryPointAccessors.fromFragment( fragment, // Fragment ExampleEntryPoint::class.java, ) val entryPoint = EntryPointAccessors.fromView( view, // View ExampleEntryPoint::class.java, )
  35. Hilt Bindings Android , . @Inject , . @Singleton class

    ExampleRepository @Inject constructor( private val local: ExampleLocalDataSource, private val remote: ExampleRemoteDataSource, ) { ... } ExampleRepository
  36. . Hilt Module Binding . @Module @InstallIn(SingletonComponent::class) class AppModule {

    @Singleton @Provides fun providesExampleRepository(...): ExampleRepository { return ExampleRepositoryImpl(...) } } Hilt Modules
  37. @Module @InstallIn(SingletonComponent::class) class AppModule { @Singleton @Provides fun providesExampleRepository( local:

    ExampleLocalDataSource, remote: ExampleRemoteDataSource, ): ExampleRepository { return ExampleRepository(local, remote) } } Hilt Modules: @Provides ExampleRepository
  38. interface ExampleRepository @Singleton class ExampleRepositoryImpl @Inject constructor(...) : ExampleRepository {

    ... } @Module @InstallIn(SingletonComponent::class) interface AppModule { @Binds fun bindsExampleRepository( impl: ExampleRepositoryImpl, ): ExampleRepository } Hilt Modules: @Binds ExampleRepositoryImpl ExampleRepository
  39. , . ( ) Binding @Qualifier . @Module @InstallIn(SingletonComponent::class) object

    DispatchersModule { @Provides fun providesDefaultDispatcher(): CoroutineDispatcher = Dispatchers.Default = @Provides fun providesIoDispatcher(): CoroutineDispatcher = Dispatchers.IO } Hilt Modules: @Qualifier
  40. @Module @InstallIn(SingletonComponent::class) object DispatchersModule { @DefaultDispatcher @Provides fun providesMainDispatcher(): CoroutineDispatcher

    = Dispatchers.Default @IoDispatcher @Provides fun providesIoDispatcher(): CoroutineDispatcher = Dispatchers.IO } Hilt Modules: @Qualifier
  41. class ExampleUseCase @Inject constructor( @DefaultDispatcher defaultDispatcher: CoroutineDispatcher, ) { ...

    } @Module @InstallIn(SingletonComponent::class) object AppModule { @Provides fun providesExampleRepository( @IoDispatcher ioDispatcher: CoroutineDispatcher, ): ExampleRepository { ... } } Hilt Modules: @Qualifier
  42. Hilt Modules: Predefined @Qualifier Hilt @Qualifier . (@ApplicationContext, @ActivityContext) Context

    . class ExampleRepository @Inject constructor( @ApplicationContext private val appContext: Context, ) { ... } class AnalyticsAdapter @Inject constructor( @ActivityContext private val activityContext: Context, ) { ... }
  43. @InstallIn , @Module Component . @Module @InstallIn(SingletonComponent::class) object ExampleModule {

    @Provides fun providesBar(foo: Foo): Bar = BarImpl(foo) @Singleton @Provides fun providesFoo(): Foo = FooImpl() } Component
  44. Scope Annotation , Component . @Module @InstallIn(SingletonComponent::class) object ExampleModule {

    // unscoped @Provides fun providesBar(foo: Foo): Bar = BarImpl(foo) @Singleton @Provides fun providesFoo(): Foo = FooImpl() } Scope
  45. Component hierarchy @Module @InstallIn(SingletonComponent::class) object AppModule { @Provides fun providesFoo():

    Foo = FooImpl() } @Module @InstallIn(ActivityComponent::class) object ActivityModule { @Provides fun providesBar(foo: Foo): Bar = BarImpl(foo) }
  46. Component hierarchy @Module @InstallIn(SingletonComponent::class) object AppModule { @Provides fun providesBaz(bar:

    Bar): Baz = BazImpl(bar) } @Module @InstallIn(ActivityComponent::class) object ActivityModule { @Provides fun providesBar(foo: Foo): Bar = BarImpl(foo) }
  47. ViewModel @HiltViewModel . , . @HiltViewModel class ExampleViewModel @Inject constructor(

    private val repository: ExampleRepository, ) : ViewModel() { ... } @AndroidEntryPoint class ExampleActivity : Activity() { private val exampleViewModel: ExampleViewModel by viewModels() } Jetpack : ViewModel
  48. @HiltWorker, @AssistedInject , Worker . @Assisted . @HiltWorker class ExampleWorker

    @AssistedInject constructor( @Assisted appContext: Context, @Assisted workerParams: WorkerParameters, private val repository: ExampleRepository, ) : Worker(appContext, workerParams) { ... } Jetpack : WorkManager
  49. // ۄ੉࠳۞ܻܳ ୶о ࢸ஖೧ঠ ೠ׮. dependencies { implementation 'androidx.hilt:hilt-work:1.0.0' kapt

    'androidx.hilt:hilt-compiler:1.0.0' } // HiltWorkerFactory۽ WorkManagerܳ ୡӝച೧ঠ ೠ׮. @HiltAndroidApp class ExampleApplication : Application(), Configuration.Provider { @Inject lateinit var workerFactory: HiltWorkerFactory override fun getWorkManagerConfiguration() = Configuration.Builder() .setWorkerFactory(workerFactory) .build() }
  50. Dagger Hilt Hilt . @HiltAndroidApp class ExampleApplication : Application() {

    @Inject lateinit var bar: Bar } @Module @InstallIn(SingletonComponent::class) object FooModule { @Provides fun provideBar(): Bar = Bar() }
  51. Dagger Hilt (1) . @HiltAndroidApp class ExampleApplication : Application() {

    @Inject lateinit var bar: Bar } @Module @InstallIn(SingletonComponent::class) object FooModule { @Provides fun provideBar(): Bar = Bar() }
  52. @HiltAndroidApp class ExampleApplication : Application() // -------------------------------------------------------------------------------- // Generated by

    Hilt public final class ExampleApplication_HiltComponents { @Component(modules = { ActivityRetainedCBuilderModule.class, ... }) @Singleton public abstract static class SingletonC implements SingletonComponent { } ... } // -------------------------------------------------------------------------------- // Generated by Dagger public final class DaggerExampleApplication_HiltComponents_SingletonC { // ੄ઓࢿ ஶప੉ց private static final class SingletonCImpl extends ExampleApplication_HiltComponents.SingletonC { public void injectExampleApplication(ExampleApplication exampleApplication) {} } ... } @HiltAndroidApp - ੄ઓࢿ ஶప੉ցܳ ࢤࢿೠ׮.
  53. Dagger Hilt (2) . @HiltAndroidApp class ExampleApplication : Application() {

    @Inject lateinit var bar: Bar } @Module @InstallIn(SingletonComponent::class) object FooModule { @Provides fun provideBar(): Bar = Bar() }
  54. ࢶ঱ೠ Componentী Module੉ ୶оػ׮. @Module @InstallIn(SingletonComponent::class) object FooModule { @Provides

    fun provideBar(): Bar = Bar() } // -------------------------------------------------------------------------------- public final class ExampleApplication_HiltComponents { @Component( modules = { ApplicationContextModule.class, ActivityRetainedCBuilderModule.class, FooModule.class, } ) @Singleton public abstract static class SingletonC implements HiltWrapper_ActivityRetainedComponentManager_ActivityRetainedComponentBuilderEntryPoint, SingletonComponent, GeneratedComponent { } }
  55. @Provides݃׮ ੄ઓࢿਸ ઁҕೞח Factory ௿ېझо ࢤࢿػ׮. @Module @InstallIn(SingletonComponent::class) object FooModule

    { @Provides fun provideBar(): Bar = Bar() } // -------------------------------------------------------------------------------- public final class FooModule_ProvideBarFactory implements Factory<Bar> { public static Bar provideBar() { return Preconditions.checkNotNullFromProvides(FooModule.INSTANCE.provideBar()); } }
  56. Dagger Hilt (3) . @HiltAndroidApp class ExampleApplication : Application() {

    @Inject lateinit var bar: Bar } @Module @InstallIn(SingletonComponent::class) object FooModule { @Provides fun provideBar(): Bar = Bar() } Hilt_ExampleApplication.java ExampleApplication_GeneratedInjector.java ExampleApplication_MembersInjector.java
  57. @HiltAndroidApp class ExampleApplication : Application() { @Inject lateinit var bar:

    Bar } = @HiltAndroidApp class ExampleApplication : Hilt_ExampleApplication() { @Inject lateinit var bar: Bar } ߄੉౟௏٘ܳ ߸ജೞৈ, ࠗݽ ௿ېझܳ ߸҃ೠ׮.
  58. Hilt_ExampleApplication.java public abstract class Hilt_ExampleApplication extends Application { private boolean

    injected = false; @CallSuper @Override public void onCreate() { if (!injected) { injected = true; ((ExampleApplication_GeneratedInjector) componentManager.generatedComponent()) .injectExampleApplication(this); } super.onCreate(); } private final ApplicationComponentManager componentManager = new ApplicationComponentManager( () -> DaggerExampleApplication_HiltComponents_SingletonC.builder() .applicationContextModule(new ApplicationContextModule(Hilt_ExampleApplication.this)) .build()); } Injector۽ SingletonCী ੽Ӕೞৈ, ੄ઓࢿ ઱ੑਸ ਃ୒ೠ׮.
  59. ExampleApplication_GeneratedInjector.java @GeneratedEntryPoint @InstallIn(SingletonComponent.class) public interface ExampleApplication_GeneratedInjector { void injectExampleApplication(ExampleApplication exampleApplication);

    } // -------------------------------------------------------------------------------- public final class ExampleApplication_HiltComponents { @Component(modules = { ... }) @Singleton public abstract static class SingletonC implements HiltWrapper_ActivityRetainedComponentManager_ActivityRetainedComponentBuilderEntryPoint, SingletonComponent, GeneratedComponent, ExampleApplication_GeneratedInjector { } } // -------------------------------------------------------------------------------- public final class DaggerExampleApplication_HiltComponents_SingletonC { private static final class SingletonCImpl extends SingletonC { public void injectExampleApplication(ExampleApplication instance) { } }
  60. ExampleApplication_MembersInjector.java @HiltAndroidApp class ExampleApplication : Application() { @Inject lateinit var

    bar: Bar } // -------------------------------------------------------------------------------- public final class ExampleApplication_MembersInjector implements MembersInjector<ExampleApplication> { public static void injectBar(ExampleApplication instance, Bar bar) { instance.bar = bar; } } // -------------------------------------------------------------------------------- public final class DaggerExampleApplication_HiltComponents_SingletonC { private static final class SingletonCImpl extends SingletonC { public void injectExampleApplication(ExampleApplication instance) { ExampleApplication_MembersInjector.injectBar( instance, FooModule_ProvideBarFactory.provideBar()); } } ࢤࢿػ Injector ௿ېझܳ ా೧, উ٘۽੉٘ ௿ېझী ੄ઓࢿ੉ ઱ੑػ׮.
  61. Dagger Hilt Dagger Hilt . ( ) Link: h tt

    ps://speakerdeck.com/fornewid, h tt ps://youtu.be/iE_2llWUI6A
  62. @AndroidEntryPoint class ExampleActivity : ComponentActivity() { @Inject lateinit var bar:

    Bar bar.doSomething() } @Module @InstallIn(SingletonComponent::class) object BarModule { @Provides fun provideBar(): Bar = Bar() }
  63. , Singleton @AndroidEntryPoint class ExampleActivity : ComponentActivity() { @Inject lateinit

    var singletonBar: SingletonBar singletonBar.doSomething() } @Module @InstallIn(SingletonComponent::class) object BarModule { @Provides fun provideBar(): SingletonBar = SingletonBar }
  64. interface-impl , Singleton interface SingletonBar { fun doSomething() } @Deprecated

    object SingletonBarImpl : SingletonBar { override fun doSomething() { ... } } @Module @InstallIn(SingletonComponent::class) object BarModule { @Provides fun provideBar(): SingletonBar = SingletonBarImpl }
  65. Hilt , Singleton interface SingletonBar { fun doSomething() } @Singleton

    class SingletonBarImpl @Inject constructor() : SingletonBar { override fun doSomething() { ... } } @Module @InstallIn(SingletonComponent::class) interface BarModule { @Binds fun bindBar(impl: SingletonBarImpl): SingletonBar }
  66. : Singleton + Context Singleton Context . class SingletonBar private

    constructor(private val context: Context) { fun doSomething() { ... } companion object { private lateinit var instance: SingletonBar fun initialize(context: Context) { instance = SingletonBar(context.applicationContext) } fun getInstance(): SingletonBar = instance } }
  67. Before class ExampleApplication : Application() { override fun onCreate() {

    super.onCreate() SingletonBar.initialize(this) } } class ExampleActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) SingletonBar.getInstance().doSomething() } }
  68. , Singleton @Module @InstallIn(SingletonComponent::class) object BarModule { @Provides fun provideBar():

    SingletonBar = SingletonBar.getInstance() } @AndroidEntryPoint class ExampleActivity : ComponentActivity() { @Inject lateinit var singletonBar: SingletonBar override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) singletonBar.doSomething() } }
  69. interface-impl , Singleton @Module @InstallIn(SingletonComponent::class) object BarModule { @Provides fun

    provideBar(): SingletonBar = SingletonBarImpl.getInstance() } interface SingletonBar { fun doSomething() } class SingletonBarImpl private constructor( context: Context ) : SingletonBar { ... }
  70. Hilt , Singleton @Module @InstallIn(SingletonComponent::class) interface BarModule { @Binds fun

    bindBar(impl: SingletonBarImpl): SingletonBar } interface SingletonBar { fun doSomething() } @Singleton class SingletonBarImpl @Inject constructor( @ApplicationContext context: Context ) : SingletonBar { ... }
  71. : Singleton + Singleton Singleton . class SingletonBar private constructor(...)

    { fun doSomething() { SingletonFoo.doSomething() } } class SingletonFoo private constructor(...) { fun doSomething() { ... } }
  72. Before class ExampleActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?)

    { super.onCreate(savedInstanceState) SingletonBar.getInstance().doSomething() } } class SingletonBar private constructor(...) { fun doSomething() { SingletonFoo.getInstance().doSomething() } } class SingletonFoo private constructor(...) { fun doSomething() { ... } }
  73. Before class SingletonBar private constructor(private val context: Context) { fun

    doSomething() { SingletonFoo.getInstance().doSomething() } } class SingletonFoo private constructor( private val context: Context ) { fun doSomething() { ... } }
  74. After class SingletonBar private constructor(private val context: Context) { private

    val singletonFoo: SingletonFoo fun doSomething() { singletonFoo.doSomething() } } @Singleton class SingletonFoo @Inject constructor( @ApplicationContext private val context: Context ) { fun doSomething() { ... } }
  75. After class SingletonBar private constructor(private val context: Context) { private

    val singletonFoo: SingletonFoo init { val entryPoint = EntryPointAccessors.fromApplication( context.applicationContext, SingletonBarEntryPoint::class.java ) singletonFoo = entryPoint.provideFoo() } } @EntryPoint @InstallIn(SingletonComponent::class) interface SingletonBarEntryPoint { fun provideFoo(): SingletonFoo }
  76. Final @Singleton class SingletonBar @Inject constructor( private val context: Context,

    private val singletonFoo: SingletonFoo, ) { fun doSomething() { singletonFoo.doSomething() } }
  77. Depth . @AndroidEntryPoint class ExampleActivity : ComponentActivity() { @Inject lateinit

    var singletonBar: SingletonBar fun doSomething() { singletonBar.doSomething() } } (3) (1) (2) app start
  78. : Component Component Component @AndroidEntryPoint . , Fragment Hilt Fragment

    Activity @AndroidEntryPoint . @AndroidEntryPoint class ExampleActivity : ComponentActivity() { ... } @AndroidEntryPoint class ExampleFragment : Fragment() { ... } ExampleActivity ExampleFragment @inject
  79. ViewModel @HiltViewModel class ExampleViewModel @Inject constructor( private val singletonBar: SingletonBar,

    ) : ViewModel() { ... } @AndroidEntryPoint class ExampleActivity : ComponentActivity() { private val viewModel: ExampleViewModel by viewModels() } class ExampleFragment : ComponentActivity() { }
  80. ViewModel @HiltViewModel class ExampleViewModel @Inject constructor( private val singletonBar: SingletonBar,

    ) : ViewModel() { ... } @AndroidEntryPoint class ExampleActivity : ComponentActivity() { // private val viewModel: ExampleViewModel by viewModels() } @AndroidEntryPoint class ExampleFragment : ComponentActivity() { private val viewModel: ExampleViewModel by viewModels() }
  81. ViewModel @HiltViewModel class ExampleViewModel @Inject constructor( private val singletonBar: SingletonBar,

    ) : ViewModel() { ... } @AndroidEntryPoint class ExampleActivity : ComponentActivity() { ... } class ExampleFragment : ComponentActivity() { private val viewModel: ExampleViewModel by activityViewModels() }
  82. : Base Base , @AndroidEntryPoint . class BaseActivity : ComponentActivity()

    { @Inject lateinit var bar: Bar } @AndroidEntryPoint class ExampleActivity : BaseActivity() { ... }
  83. #1: @AndroidEntryPoint . , . @AndroidEntryPoint class ExampleActivity : AppCompatActivity()

    { @Inject lateinit var bar: Bar override fun attachBaseContext(base: Context) { super.attachBaseContext(bar.newContext(base)) } } Link: h tt ps://stackove rf low.com/a/64162926
  84. #2: Generic Base Generic , . @AndroidEntryPoint class ExampleActivity :

    BaseActivity<Something>() { ... } Link: h tt ps://github.com/google/dagger/issues/3370
  85. App Modularization: @Module Hilt Module , . :app:android :feature:home :data:books

    :feature:reviews :feature:player :app:auto :core:network :data:reviews @Module @Module @Module
  86. App Modularization: @Module @HiltAndroidApp Hilt Module . :app:android :feature:home :data:books

    :core:network @Module @InstallIn(SingletonComponent::class) object FeatureHomeModule { ... } @Module @InstallIn(SingletonComponent::class) object DataBooksModule { ... } @Module @InstallIn(SingletonComponent::class) object CoreNetworkModule { ... } @HiltAndroidApp class MyApp : Application()
  87. Without Classpath Aggregation @Module . hilt_metadata :app:android :feature:home :data:books :core:network

    implementation implementation api @Metadata @Metadata @InstallIn @InstallIn @InstallIn @Generated("dagger.hilt") interface MyApp_HiltComponents { @Component(modules = [ FeatureHomeModule::class, DataBooksModule::class, ... ]) interface SingletonC } CoreNetworkModule::class, Link: h tt ps://medium.com/androiddevelopers/mad-skills-series-hilt-under-the-hood-9d89ee227059
  88. With Classpath Aggregation Classpath Aggregation , . hilt_metadata :app:android :feature:home

    :data:books :core:network implementation implementation api @Metadata @Metadata @Metadata @InstallIn @InstallIn @InstallIn @Generated("dagger.hilt") interface MyApp_HiltComponents { @Component(modules = [ FeatureHomeModule::class, DataBooksModule::class, ... ]) interface SingletonC } CoreNetworkModule::class, Link: h tt ps://medium.com/androiddevelopers/mad-skills-series-hilt-under-the-hood-9d89ee227059
  89. App Architecture Hilt , . :data class ExampleUseCase @Inject constructor(

    private val repository: ExampleRepository ) { ... } :ui :domain class ExampleRepository @Inject constructor( ) { ... }
  90. App Architecture: interface, class , :domain :data class ExampleUseCase @Inject

    constructor( private val repository: ExampleRepository ) { ... } class ExampleRepository @Inject constructor( ) { ... }
  91. App Architecture: interface, class interface class , . :domain :data

    interface ExampleRepository class ExampleRepositoryImpl @Inject constructor( ) : ExampleRepository { ... } @Module @InstallIn(SingletonComponent::class) interface DataModule { @Binds fun bindRepository( impl: ExampleRepositoryImpl ) : ExampleRepository } class ExampleUseCase @Inject constructor( private val repository: ExampleRepository ) { ... }
  92. App Architecture: internal , internal . :domain :data interface ExampleRepository

    internal class ExampleRepositoryImpl @Inject constructor( ) : ExampleRepository { ... } @Module @InstallIn(SingletonComponent::class) internal interface DataModule { @Binds fun bindRepository( impl: ExampleRepositoryImpl ) : ExampleRepository } class ExampleUseCase @Inject constructor( private val repository: ExampleRepository ) { ... }
  93. internal @Module , HiltWrapper internal @Module @OriginatingElement(topLevelClass = DataModule.class) @InstallIn(SingletonComponent.class)

    @Module(includes = DataModule.class) public final class HiltWrapper_DataModule {} @Module @InstallIn(SingletonComponent::class) internal interface DataModule { @Binds fun bindRepository(impl: ExampleRepositoryImpl) : ExampleRepository }
  94. internal @Module ؀न Componentী ୶о೧ળ׮. Ӓ۞ա… public final class ExampleApplication_HiltComponents

    { @Component( modules = { ApplicationContextModule.class, ActivityRetainedCBuilderModule.class, HiltWrapper_DataModule.class, } ) @Singleton public abstract static class SingletonC implements HiltWrapper_ActivityRetainedComponentManager_ActivityRetainedComponentBuilderEntryPoint, SingletonComponent, GeneratedComponent { } }
  95. App Architecture: interface class . :domain-qux :domain-bar-api :domain-baz :domain-bar-impl interface

    Bar class BarImpl(foo: Foo) : Bar interface Qux class QuxImpl(bar: Bar) : Qux interface Baz class BazImpl(bar: Bar) : Baz
  96. App Architecture: @Module . :domain-qux :domain-bar-api :domain-baz :domain-bar-impl interface Bar

    class BarImpl(foo: Foo) : Bar -> interface Qux class QuxImpl(bar: Bar) : Qux @Module interface Baz class BazImpl(bar: Bar) : Baz
  97. App Architecture: (DIP) . :domain-qux-impl :domain-baz-impl :domain-bar-impl :domain-foo-impl class BazImpl(bar:

    Bar) : Baz class BarImpl(foo: Foo) : Bar class FooImpl() : Foo class QuxImpl(baz: Baz) : Qux :domain-qux-api :domain-baz-api :domain-bar-api :domain-foo-api interface Baz interface Bar interface Foo interface Qux Link: h tt ps://en.wikipedia.org/wiki/Dependency_inversion_principle
  98. App Modularization: Final! (+ runtimeOnly) , . :app:android :feature:home-api :data:books-api

    :data:books-impl runtimeOnly :app:android :feature:home :data:books :feature:home-impl runtimeOnly Before After
  99. , . , DI . Dagger Hilt . Component, Scope,

    Module, @Inject, @AndroidEntryPoint, … . Dagger Hilt , .
  100. !