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

의존성 주입과 모듈화

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.

의존성 주입과 모듈화

2026년 4월 15일 (수) 삼성전자에서의 발표자료입니다.

Avatar for Sungyong An

Sungyong An

April 15, 2026

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.getEngine() }

    object ServiceLocator { fun getEngine() : Engine = Engine() } fun main(args: Array) { val car = Car() car.start() } Service Locator Engine Car Service Locator
  9. class CarTest { @Test fun `Car happy path`() { ServiceLocator.set(FakeEngine())

    val car = Car() } @Test fun `Car with failing Engine`() { ServiceLocator.set(FakeFailingEngine()) val car = Car() // ׮ܲ పझ౟৬ ୽ج! } } Service Locator
  10. class Car { private val engine = ServiceLocator.get() // Carо

    Engineী ੄ઓೞח૑ ৻ࠗীࢲח ঌ ࣻ হ׮ } Service Locator
  11. ? . Android Studio Dagger/Hilt . DI . DI ,

    . Link: h tt ps://medium.com/androiddevelopers/dagger-navigation-suppo rt -in-android-studio-49aa5d149ec9
  12. 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
  13. 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
  14. 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
  15. class AppContainer { val database = Database() val network =

    Network() } 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.database, appContainer.network) viewModel.doSomething() } }
  17. 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() }
  18. 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) // Singleton viewModel.doSomething() } }
  19. 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.getExampleRepository()) // New! viewModel.doSomething() } }
  20. class AppContainer { private val database = Database() private val

    network = Network() private val localDataSource = ExampleLocalDataSource(database) private val remoteDataSource = ExampleRemoteDataSource(network) fun getExampleRepository() : ExampleRepository { return ExampleRepository(localDataSource, remoteDataSource) // New! } }
  21. // Application ࠁ׮ ੘਷ ߧਤ੄ ੄ઓࢿ ஶప੉ց 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
  22. 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
  23. 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
  24. 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 …
  25. Dagger Hilt Android DI Android , . (Application, Activity, Service,

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

    Engine = Engine() } Engine @Provides ١ਸ ੉ਊೞৈ, ੄ઓࢿਸ ઁҕೡ ࣻ ੓׮.
  27. @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ܳ ੉ਊೞৈ, ੄ઓࢿਸ ௿ېझ ࢤࢿ੗ী ઱ੑೡ ࣻ ੓׮.
  28. @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 ௿ېझח ࢤࢿ੗о ইצ, ೙٘ী ੄ઓࢿਸ ઱ੑೠ׮.
  29. @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ਸ ӝ߈ਵ۽, ੄ઓࢿਸ ઱ੑೞח ௏٘ܳ ࢤࢿ೧ળ׮.
  30. // project’s root build.gradle buildscript { repositories { mavenCentral() }

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

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

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

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

    : ComponentActivity() { @Inject lateinit var data: ExampleData } ... ExampleActivity ExampleData
  35. @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() { ... }
  36. @AndroidEntryPoint // X class ExampleContentProvider : ContentProvider() { ... }

    // Activity, Fragment, View, Service, BroadcastReceiverо ইצ, // ׮ܲ Android ௿ېझীח @AndroidEntryPointܳ ࢎਊೡ ࣻ হ׮.
  37. 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()
  38. class ExampleContentProvider : ContentProvider() { override fun query(...): Cursor {

    val appContext = context?.applicationContext ?: throw Exception() val entryPoint = EntryPointAccessors.fromApplication( appContext, ExampleEntryPoint::class.java ) val foo = entryPoint.foo() ... } }
  39. @Composable private fun rememberFoo(): Foo { val context = LocalContext.current

    return remember { val entryPoint = EntryPointAccessors.fromApplication( context.applicationContext, ExampleEntryPoint::class.java, ) entryPoint.foo() } } @Composable fun ExampleComposable() { val foo: Foo = rememberFoo() ... }
  40. 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, )
  41. Hilt Bindings Android , . @Inject , . @Singleton class

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

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

    ExampleLocalDataSource, remote: ExampleRemoteDataSource, ): ExampleRepository { return ExampleRepository(local, remote) } } Hilt Modules: @Provides ExampleRepository
  44. 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
  45. , . ( ) Binding @Qualifier . @Inject lateinit var

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

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

    } @Module @InstallIn(SingletonComponent::class) object AppModule { @Provides fun providesExampleRepository( @IoDispatcher ioDispatcher: CoroutineDispatcher, ): ExampleRepository { ... } } Hilt Modules: @Qualifier
  48. 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, ) { ... }
  49. @InstallIn , @Module Component . @Module @InstallIn(SingletonComponent::class) object ExampleModule {

    @Provides fun providesBar(foo: Foo): Bar = BarImpl(foo) @Singleton @Provides fun providesFoo(): Foo = FooImpl() } Component
  50. 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
  51. 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) }
  52. 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) }
  53. : Provider @AndroidEntryPoint class ExampleActivity : ComponentActivity() { @Inject lateinit

    var data: Provider<ExampleData> ... data.get() // ੉ द੼ী ࢤࢿػ׮. ױ, ݒߣ ࢜۽਍ ё୓о ٜ݅য૓׮. ... } @Inject , . Provider get() . .
  54. : Lazy Lazy get() , . . @AndroidEntryPoint class ExampleActivity

    : ComponentActivity() { @Inject lateinit var data: Lazy<ExampleData> ... data.get() // ੉ द੼ী ё୓о ࢤࢿػ׮. ױ, ৈ۞ߣ ഐ୹ೞݶ ੉޷ ࢤࢿػ ё୓о ߈ജػ׮. ... }
  55. ViewModel @HiltViewModel . , . @HiltViewModel class ExampleViewModel @Inject constructor(

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

    @AssistedInject constructor( @Assisted appContext: Context, @Assisted workerParams: WorkerParameters, private val repository: ExampleRepository, ) : Worker(appContext, workerParams) { ... } Jetpack : WorkManager
  57. // ۄ੉࠳۞ܻܳ ୶о ࢸ஖೧ঠ ೠ׮. 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() }
  58. @AndroidEntryPoint class ExampleActivity : ComponentActivity() { @Inject lateinit var bar:

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

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

    ... } } @Module @InstallIn(SingletonComponent::class) object BarModule { @Provides fun provideBar(): SingletonBar = SingletonBar }
  61. After: 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 }
  62. After: 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 }
  63. (1-B) : 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 } }
  64. 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() } }
  65. After: , 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() } }
  66. After: interface-impl , Singleton @Module @InstallIn(SingletonComponent::class) object BarModule { @Provides

    fun provideBar(): SingletonBar = SingletonBarImpl.getInstance() } interface SingletonBar { fun doSomething() } @Deprecated class SingletonBarImpl private constructor( context: Context ) : SingletonBar { ... }
  67. After: 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 { ... }
  68. class ExampleApplication : Application() { override fun onCreate() { super.onCreate()

    // SingletonBar.initialize(this) } } After: Hilt Singleton
  69. (1-C) : Singleton + Singleton Singleton . class SingletonBar private

    constructor(...) { fun doSomething() { SingletonFoo.doSomething() } } class SingletonFoo private constructor(...) { fun doSomething() { ... } }
  70. 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() { ... } }
  71. Before class SingletonBar private constructor(private val context: Context) { fun

    doSomething() { SingletonFoo.getInstance().doSomething() } } class SingletonFoo private constructor( private val context: Context ) { fun doSomething() { ... } }
  72. 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() { ... } }
  73. 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 }
  74. Final @Singleton class SingletonBar @Inject constructor( private val context: Context,

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

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

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

    ) : ViewModel() { ... } @AndroidEntryPoint class ExampleActivity : ComponentActivity() { private val viewModel: ExampleViewModel by viewModels() } class ExampleFragment : ComponentActivity() { }
  78. 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() }
  79. ViewModel @HiltViewModel class ExampleViewModel @Inject constructor( private val singletonBar: SingletonBar,

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

    ComponentActivity() { @Inject lateinit var bar: Bar } @AndroidEntryPoint class ExampleActivity : BaseActivity() { ... }
  81. , . , DI . Dagger Hilt . Component, Scope,

    Module, @Inject, @AndroidEntryPoint, … .
  82. ? A app B data app domain or app app

    common C domain app app data app app feature app app app or
  83. App Architecture Modularization • UI Layer • Domain Layer (Optional)

    • Data Layer 1:1 . • App Modules • Feature Modules • Data Modules • Common Modules • Test Modules
  84. , . (ex. Common Data Feature) (1) Version Catalog (2)

    Data (3) BuildCon fi g (4) Common (5) Convention Plugins (6) Feature
  85. (1) Version Catalog . (ex. Kotlin, Dagger Hilt) Version Catalog

    , . 2023 Gradle Version Catalog 저 ᆨ 용하기
  86. // build.gradle dependencies { implementation 'androidx.core:core-ktx:1.9.0' } // gradle/libs.versions.toml [versions]

    androidx-core-ktx = "1.9.0" [libraries] androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidx-core-ktx" } // build.gradle dependencies { implementation libs.androidx.core.ktx }
  87. (2) Data , . data: API, DB, SharedPreferences, DataStore Repository,

    DataSource, DTO, Entity model: (ex. DTO, Enity annotation) Java, Kotlin :data :model :app
  88. // :data module interface ExampleRepository { suspend fun getExampleList(): List<Example>

    } internal class ExampleRepositoryImpl(...) : ExampleRepository { ... } internal interface ExampleRemoteDataSource { ... } internal class ExampleRemoteDataSourceImpl(...) : ExampleRemoteDataSource { ... } internal class ExampleResponse(val something: String) internal interface ExampleLocalDataSource { ... } internal class ExampleLocalDataSourceImpl(...) : ExampleLocalDataSource { ... } internal class ExampleEntity(val something: String) // :model module class Example(val something: String) Repository৬ Model ௿ېझ ৻ীח, internel ఃਕ٘ܳ ੉ਊೞৈ ੽Ӕਸ ઁೠೠ׮.
  89. (2) Data Legacy DB, SharedPreferences . interface app , data

    . :app :data AppPreferences LegacyRemoteDataSource LegacyPreferences ExampleViewModel ExampleRepository ExampleApi ExamplePreferences ExamplePreferencesImpl ExampleRepositoryImpl internal LegacyLocalDataSource ExampleDatabase
  90. // :data module interface LegacyPreferences { var something: String }

    interface ExamplePreferences : LegacyPreferences { ... } internal class ExamplePreferencesImpl( context: Context, private val legacyPrefs: LegacyPreferences, ) : ExamplePreferences, LegacyPreferences by legacyPrefs { ... } // :app module object AppPreferences : LegacyPreferences { override var something: String = ... } inte rf aceܳ ੉ਊೞৈ, app ݽٕ੄ Singletonਸ data ݽٕী ઁҕೡ ࣻ ੓׮.
  91. // :app module @Module @InstallIn(SingletonComponent::class) object AppModule { @Provides fun

    providesLegacyPreferences() : LegacyPreferences { return AppPreferences } } Hiltܳ ੉ਊೞৈ, ੄ઓࢿਸ ࢜۽਍ inte rf ace۽ ઁҕೡ ࣻ ੓׮.
  92. // How to use - val something = AppPreferences.something +

    @Inject + lateinit var prefs: ExamplePreferences + + val something = prefs.something ੉ઁ ࢎਊೞ؍ ࠗ࠙ਸ ೞաঀ ੹ജೡ ࣻ ੓׮.
  93. // :app module android { defaultConfig { buildConfigField "String", "VERSION_NAME",

    “String.valueOf(\"1.0.0\")" } flavorDimensions "default" productFlavors { dev { buildConfigField "String", "API_BASE_URL", "String.valueOf(\"https://dev...\")" } stage { buildConfigField "String", "API_BASE_URL", "String.valueOf(\"https://stage...\")" } real { buildConfigField "String", "API_BASE_URL", "String.valueOf(\"https://real...\")" } } } ࠁా fl avorী ٮۄ ч੉ ׳ۄ૑ח ࢎਊ੗ ੿੄ ೙٘ܳ ୶оೞৈ ࢎਊೠ׮. Link: h tt ps://developer.android.com/build/gradle-tips#share-custom- fi elds-and-resource-values-with-your-app-code
  94. (3) BuildConfig BuildCon fi g.DEBUG BuildCon fi g.VERSION_NAME BuildCon fi

    g.API_BASE_URL (custom) data BuildConfig : (1) app .
  95. (3) BuildConfig BuildCon fi g.DEBUG BuildCon fi g.VERSION_NAME BuildCon fi

    g.API_BASE_URL (custom) data BuildConfig : (1) app . (2) BuildConfig .
  96. // :app module dependencies { implementation project(':buildconfig') } // :data

    module dependencies { implementation project(':buildconfig') } ೧஖ਛա…?
  97. // :buildconfig module android { namespace 'soup.movie.buildconfig' defaultConfig { buildConfigField

    "String", "VERSION_NAME", “String.valueOf(\"1.0.0\")" } buildFeatures { buildConfig true } flavorDimensions "default" productFlavors { dev { buildConfigField "String", "API_BASE_URL", "String.valueOf(\"https://dev...\")" } stage { buildConfigField "String", "API_BASE_URL", "String.valueOf(\"https://stage...\")" } real { buildConfigField "String", "API_BASE_URL", "String.valueOf(\"https://real...\")" } } } ੄ઓࢿਸ ыח ݽٚ ݽٕী fl avorо ੹౵غח ޙઁ੼.
  98. // :data module android { buildFeatures { buildConfig false }

    flavorDimensions "default" productFlavors { dev {} dev2 {} stage {} real {} } } ೧Ѿೡ ࣻ ੓ח ߑߨ੉ ੓ਸө…? // :app module android { buildFeatures { buildConfig false } flavorDimensions "default" productFlavors { dev {} dev2 {} stage {} real {} } }
  99. // :buildconfig-stub module android { namespace 'soup.movie.buildconfig' defaultConfig { buildConfigField

    "String", "VERSION_NAME", "String.valueOf(\"0\")" buildConfigField "String", "API_BASE_URL", "String.valueOf(\"\")" } buildFeatures { buildConfig true } // productFlavors X } (1) fl avorо হח, stub ݽٕਸ ୶оೠ׮.
  100. // :app module dependencies { implementation project(':buildconfig') } // :data

    module dependencies { compileOnly project(':buildconfig-stub') } (2) fl avorо ੓ח app ݽٕ ৻ীח stubਸ compileOnly۽ ࢶ঱ೠ׮.
  101. (3) BuildConfig compileOnly , . , buildconfig-stub , buildconfig .

    , flavor . :data :app :buildcon fi g :buildcon fi g-stub compileOnly implementation = :others … Link: h tt ps://developer.android.com/build/dependencies#dependency_con fi gurations
  102. :app :data :buildcon fi g :buildcon fi g-stub :model compileOnly

    ੉ߣীח app ݽٕীࢲ feature ݽٕਸ աׇࠁ੗.
  103. Feature Common (?) feature . : color, dimen, drawable, string,

    style, … Base : Activity, Fragment, Dialog, … Widget, , , . . data ? :app :feature-common :data :feature:search :model api ?
  104. (4) Common , . kotlin: Kotlin, Coroutines logger: Log designsystem:

    resources: … :common :data :feature:search :kotlin :logger :resources :designsystem api … Link: h tt ps://developer.android.com/topic/modularization/pa tt erns#common-modules
  105. (4) Common resources ID R . non-transitive R , R

    . ( ) , R import . com.myapp.library2.R welcome_text = Hi, Songdo com.myapp.library1.R welcome_text = Hi, Songdo goodbye_text = Bye :library2 module welcome_text = Hi, Songdo :library1 module goodbye_text = Bye com.myapp.library.R welcome_text = Hi, Songdo com.myapp.library1.R goodbye_text = Bye non-transitive R classes Link: h tt ps://developer.android.com/build/optimize-your-build#use-non-transitive-r-classes
  106. // gradle.properties android.nonTransitiveRClass=true // :library2 module import com.myapp.library2.R val bar

    = R.string.welcome_text // :library1 module import com.myapp.library1.R - val foo = R.string.welcome_text + val foo = com.myapp.library2.R.string.welcome_text val bar = R.string.goodbye drawable, string, color ١ ܻࣗझܳ ೞա੄ ݽٕী فݶ…? Link: h tt ps://medium.com/androiddevelopers/5-ways-to-prepare-your-app-build-for-android-studio- fl amingo-release-da34616bb946
  107. // gradle.properties android.nonTransitiveRClass=true // :library2 module - import com.myapp.library2.R +

    import com.myapp.resources.R val bar = R.string.welcome_text // :library1 module - import com.myapp.library1.R + import com.myapp.resources.R val foo = R.string.welcome_text val bar = R.string.goodbye impo r ܳ ҙܻೞӝ ಞೞ׮. Link: h tt ps://medium.com/androiddevelopers/5-ways-to-prepare-your-app-build-for-android-studio- fl amingo-release-da34616bb946
  108. (4) Common resources , override . override . com.myapp.library2.R welcome_text

    = Hi, Incheon com.myapp.library1.R welcome_text = Hi, Incheon :library2 module welcome_text = Hi, Songdo :library1 module welcome_text = Hi, Incheon Link: h tt ps://developer.android.com/studio/projects/android-library#Considerations
  109. // :library2 module android { resourcePrefix 'myapp_lib2_' } <string name="welcome_text">Hi,

    Songdo</string> // :library1 module android { resourcePrefix 'myapp_lib1_' } <string name="welcome_text">Hi, Incheon</string> // :app module val foo = R.string.myapp_lib2_welcome_text // Hi, Songdo val bar = R.string.myapp_lib1_welcome_text // Hi, Incheon (1) resourcePre fi xܳ ੉ਊೞח ߑߨ. ೞ૑݅ ৻ࠗ ۄ੉࠳۞ܻীࢲ Ҁ஘׮ݶ…? Link: h tt ps://developer.android.com/reference/tools/gradle-api/8.2/com/android/build/api/dsl/CommonExtension#resourcePre fi x()
  110. // 3rd party library <string name="app_name">3rd Party Library</string> // :common:resources

    module <string name="app_name">MyApp</string> // :app module android { sourceSets { main.res.srcDirs += '../common/resources/src/main/res' } } val foo = R.string.app_name // MyApp (2) জ ݽٕ੄ sourceSetsী ܻࣗझ ݽٕ੄ ಫ؊ܳ ୶оೞח ߑߨ. Link: h tt ps://developer.android.com/build/build-variants#con fi gure-sourcesets
  111. (5) Convention Plugins . , + . 2023 Gradle Kotlin

    Link: h tt ps://docs.gradle.org/current/samples/sample_convention_plugins.html
  112. plugins { id 'com.android.library' id 'org.jetbrains.kotlin.android' } android { compileSdk

    34 defaultConfig { minSdk 21 targetSdk 34 } compileOptions { sourceCompatibility JavaVersion.VERSION_11 targetCompatibility JavaVersion.VERSION_11 } kotlinOptions { jvmTarget = '11' } } plugins { id 'example.android.library' } ߈ࠂغח ௏٘ܳ ઴ੌ ࣻ ੓׮.
  113. plugins { id 'com.google.dagger.hilt.android' id 'org.jetbrains.kotlin.kapt' } dependencies { implementation

    libs.hilt.android kapt libs.hilt.compiler } plugins { id 'example.android.hilt' } ݽٕ݃׮ pluginਸ ٜ݅ӝࠁ׮ח, ੤ഝਊೡ ࣻ ੓ח ױਤ۽ ա־ח Ѫ੉ જ׮.
  114. // :feature:search module plugins { id 'example.android.library' id 'example.android.hilt' }

    dependencies { implementation project(':common:kotlin') implementation project(':common:logger') implementation project(':common:designsystem') implementation project(':common:resources') implementation project(':data') implementation project(':model') } // :feature:search module plugins { id 'example.android.feature' } ੸੺൤ ա־ݶ ݻ ઴݅ਵ۽ ୡӝചೡ ࣻ ੓Ҋ, ޘযࢲ ࢎਊೡ ࣻب ੓׮.
  115. (6) Feature , . home: detail: search: settings: navigator: …

    Link: h tt ps://developer.android.com/topic/modularization/pa tt erns#feature-modules :feature :app :home :search :se tt ings :data :navigator :detail
  116. // :feature:detail module <manifest> <application> <activity android:name=".DetailActivity"/> </application> </manifest> //

    :feature:home module startActivity(Intent(context, DetailActivity::class.java) э਷ ݽٕীࢲח Activityܳ ૒੽ ଵઑೡ ࣻ ੓૑݅, ׮ܲ ݽٕ੉ۄݶ…?
  117. // :feature:detail module <manifest> <application> <activity android:name=".DetailActivity" android:exported="true"> <intent-filter> ...

    <data android:scheme="..." android:host="detail" /> </intent-filter> </activity> </application> </manifest> // :feature:home module startActivity(Intent(ACTION_VIEW, Uri.parse("...://detail")) ٩݂௼ب оמೞ׮. ೞ૑݅ ৻ࠗীب Activityо ֢୹ػ׮.
  118. // :feature:detail module <manifest> <application> <activity android:name=".DetailActivity" android:exported="true"> <intent-filter> ...

    <data android:scheme="..." android:host="detail" /> </intent-filter> </activity> </application> </manifest> // :feature:home module startActivity(Intent(ACTION_VIEW, Uri.parse("...://detail?id=...")) ӒܻҊ ID э਷ чਸ ੹׳೧ঠ ೠ׮ݶ…?
  119. (6) Feature navigator Feature , . :app :feature :home :detail

    .DetailActivity .HomeActivity :navigator Navigator NavigatorImpl
  120. // :feature:navigator module sealed interface Destination class Detail(val id: String)

    : Destination interface Navigator { fun createIntent(destination: Destination): Intent } // :feature:detail module class NavigatorImpl(private val context: Context) : Navigator { override fun createIntent(destination: Destination) { return when (destination) { is Detail -> Intent(context, DetailActivity::class.java) .putExtra(DetailActivity.EXTRA_ID, destination.id) ... } } } Activityী ੽Ӕೡ ࣻ ੓ח Ҕী ҳഅ୓ܳ ݅ٚ׮.
  121. // :feature:detail module <manifest> <application> <activity android:name=".DetailActivity" android:exported="false"/> </application> </manifest>

    // :feature:home module startActivity(navigator.createIntent(Detail(id = ...))) ৻ࠗী Activityܳ ֢୹ೞ૑ ঋҊ, ݽٕ р ചݶਸ ੉زೡ ࣻ ੓׮.
  122. (6) Feature navigator Activity , Fragment . :app :feature :home

    :detail .DetailFragment .HomeFragment :navigator FragmentFactory FragmentFactoryImpl
  123. // :feature:navigator module sealed interface FragmentDestination class Detail(val id: String)

    : FragmentDestination interface FragmentFactory { fun createFragment(destination: FragmentDestination): Fragment } // :app module class FragmentFactoryImpl : FragmentFactory { override fun createFragment(destination: FragmentDestination): Fragment { return when (destination) { is Detail -> DetailFragment.newInstance(id = destination.id) ... } } } Fragmentী ੽Ӕೡ ࣻ ੓ח Ҕী ҳഅ୓ܳ ݅ٚ׮.
  124. // :feature:detail module class DetailFragment : Fragment() { ... companion

    object { fun newInstance(id: String): DetailFragment { ... } } } // :feature:home module fragmentManager.commit { val fragment = navigator.createFragment(Detail(id = ...)) add(R.id.fragment_view_container, fragment) } ݽٕ рী Fragmentܳ ҕਬೞৈ ࢎਊೡ ࣻ ੓׮.
  125. ? :app :feature:se tt ings :feature:search :feature:navigator :data Link: h

    tt ps://developer.android.com/topic/modularization
  126. internal . ( ) Link: h tt ps://kotlinlang.org/docs/visibility-modi fi ers.html#modules

    :feature:search :data interface SearchRepository internal class SearchRepositoryImpl( ... ) : SearchRepository { ... } @Module @InstallIn(SingletonComponent::class) internal interface DataModule { @Provids fun provideSearchRepository(...) : SearchRepository { ... } } @HiltViewModel class SearchViewModel @Inject constructor( private val repository: SearchRepository, ) : ViewModel() { ... }
  127. Domain Layer , Data . UseCase . ( ) Link:

    h tt ps://developer.android.com/topic/architecture/domain-layer#data-access-restriction UI Layer Domain Layer Data Layer
  128. // :ui module class ExampleViewModel @Inject constructor( private val repository:

    ExampleRepository // X private val usecase: ExampleUseCase, ) { ... } // :domain module class ExampleUseCase( private val repository: ExampleRepository ) { ... } // :data module interface ExampleRepository { ... } internal class ExampleRepositoryImpl(...) : ExampleRepository { ... } :ui :domain :data
  129. Data Domain ? (DIP) app . ( ) impl ,

    internal . Link: h tt ps://developer.android.com/topic/architecture/domain-layer#data-access-restriction UI Layer Domain Layer Data Layer App
  130. // :ui module class ExampleViewModel @Inject constructor( private val usecase:

    ExampleUseCase, private val repository: ExampleRepository // O ) { ... } // :domain module class ExampleUseCase @Inject constructor( private val repository: ExampleRepository ) { ... } interface ExampleRepository { ... } // :data module internal class ExampleRepositoryImpl(...) : ExampleRepository { ... } Domain ݽٕী Dataо ೣԋ ੓ח Ѫ੉ ݏਸө…? :ui :domain :data
  131. -api, -impl , internal . runtimeOnly , -impl . Link:

    h tt ps://developer.android.com/build/dependencies#dependency_con fi gurations :feature:search :data-api :data-impl runtimeOnly
  132. // :feature:search module dependencies { implementation project(':data-api') runtimeOnly project(':data-impl') }

    // :data-impl module dependencies { implementation project(':data-api') } // :data-api module dependencies { ... } :feature:search :data-impl :data-api runtimeOnly
  133. // :feature-common module abstract class BaseActivity : AppCompatActivity { @Inject

    lateinit var getCurrentLanguage: GetCurrentLanguageUseCase } // :feature:settings module interface GetCurrentLanguageUseCase { operator fun invoke(): Language } class LanguageSettingActivity : BaseActivity() { ... } :feature ৘ܳ ٜয, Feature ݽٕী UI৬ Domain ۨ੉যо ҕઓೞח ҃਋. :feature-common :se tt ings
  134. -api, -impl , . :feature-common :feature :se tt ings-api :app

    :se tt ings-impl runtimeOnly Link: h tt ps://en.wikipedia.org/wiki/Circular_dependency
  135. // :feature-common module abstract class BaseActivity : AppCompatActivity { @Inject

    lateinit var getCurrentLanguage: GetCurrentLanguageUseCase } // :feature:settings-api module interface GetCurrentLanguageUseCase { operator fun invoke(): Language } // :feature:settings-impl module class GetCurrentLanguageUseCaseImpl : GetCurrentLanguageUseCase { ... } class LanguageSettingActivity : BaseActivity() { ... } :feature-common :feature :se tt ings-api :se tt ings-impl impl ݽٕ਷ api ݽٕਸ ଵઑೞҊ, ৉ਵ۽ח ೡ ࣻ হ׮.
  136. -api, -impl -impl app , -impl . :app :feature:search-impl :feature-common

    :feature:navigator-impl :data :feature:search-api :feature:navigator-api runtimeOnly runtimeOnly
  137. data -api, -impl . . Link: h tt ps://developer.android.com/topic/modularization/pa tt

    erns#how_to_implement :data-impl :app :feature:search-impl :feature-common :feature:navigator-impl :data-api :feature:search-api :feature:navigator-api runtimeOnly runtimeOnly
  138. (7) Feature . -api: UseCase interface UI (Widget, ViewHolder )

    -impl: UseCase class UI (Activity, Fragment, ViewModel ) :feature :app :search-impl :se tt ings-impl :se tt ings-api UseCase :search-api
  139. (7) Feature navigator runtimeOnly , Activity . :app :feature :home-impl

    :detail-impl .DetailActivity .HomeActivity :navigator Navigator NavigatorImpl
  140. (7) Feature navigator Activity -impl -NavigatorImpl . :feature :navigator-impl :home-impl

    :detail-impl DetailNavigatorImpl HomeNavigatorImpl :navigator-api Navigator NavigatorImpl HomeNavigator DetailNavigator
  141. // :feature:navigator module sealed interface Destination class Detail(val id: String)

    : Destination // :app module class NavigatorImpl(private val context: Context) : Navigator { override fun createIntent(destination: Destination) { return when (destination) { is Detail -> Intent(context, DetailActivity::class.java) // X ... } } } জ ݽٕীࢲח -impl ݽٕ੄ Activityী ੽Ӕೡ ࣻ হ׮.
  142. // :feature:navigator-api module interface DetailNavigator { fun createIntent(destination: Detail): Intent

    } // :feature:detail-impl module class DetailNavigatorImpl(private val context: Context) : DetailNavigator { override fun createIntent(destination: Detail): Intent { return Intent(context, DetailActivity::class.java) // O } } // :feature:navigator-impl module class NavigatorImpl(private val detailNavigator: DetailNavigator) : Navigator { override fun createIntent(destination: Destination) { ... } } Activityо ੓ח -impl ݽٕীࢲ -NavigatorImplਸ ҳഅೞݶ ػ׮.
  143. (8) Data . , Conflict . :data :home-impl :detail-impl :search-impl

    :database-impl :network-impl model … :home-api :detail-api :search-api :network-api :database-api
  144. :data :feature :navigator-impl :navigator-api :common :app :common :designsystem :logger :buildcon

    fi g :buildcon fi g-stub :resources compileOnly … :search-impl :search-api :detail-impl :detail-api :search-api :search-impl :detail-api :detail-impl …
  145. :data :feature :navigator-impl :navigator-api :common :app :common :designsystem :logger :buildcon

    fi g :buildcon fi g-stub :resources compileOnly … :search-impl :search-api :detail-impl :detail-api :search-api :search-impl :detail-api :detail-impl … :search-sample :detail-sample :designsystem-sample
  146. App Modularization: @Module Hilt @Module , . :app:android :feature:home :data:books

    :feature:reviews :feature:player :app:auto :core:network :data:reviews @Module @Module @Module
  147. 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()
  148. 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
  149. With Classpath Aggregation Classpath Aggregation , . (Gradle Plugin )

    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
  150. App Architecture Hilt , . :data class ExampleUseCase @Inject constructor(

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

    constructor( private val repository: ExampleRepository ) { ... } class ExampleRepository @Inject constructor( ) { ... }
  152. 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 ) { ... }
  153. 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 ) { ... }
  154. 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 }
  155. 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 { } }
  156. 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
  157. 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
  158. 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
  159. 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
  160. App Modularization: Final! (+ runtimeOnly) // app/build.gradle dependencies { implementation(projects(":feature:home-api"))

    - implementation(projects(":feature:home-impl")) + runtimeOnly(projects(":feature:home-impl")) ... } // feature/home-impl/build.gradle dependencies { implementation(projects(":feature:home-api")) }
  161. Git Merge Conflict . . , Application . :app :feature

    :home HomeData MyApplication :search SearchData
  162. // :app module class MyApplication : Application() { override fun

    onCreate() { ... <<<<<<< HEAD HomeData.preload() ======= SearchData.preload() >>>>>>> ... } } ࢲ۽ ׮ܲ PRীࢲ ୡӝച ೣࣻܳ ୶оೞݶ, Con fl ict੉ ߊࢤೠ׮.
  163. Dagger Hilt app feature , feature app . :app :feature

    :home-impl HomeInitializer :sta rt up-api Initializer Set<Initializer> :search-impl SearchInitializer
  164. // :feature:search-impl module @Module @InstallIn(SingletonComponent::class) interface SearchModule { @IntoSet @Binds

    fun bindsInitializer(impl: SearchInitializer): Initializer } class SearchInitializer @Inject constructor() : Initializer { override operator fun invoke() { SearchData.preload(...) } } // :app module @HiltAndroidApp class MyApplication : Application() { @Inject lateinit var initializerSet: Set<@JvmSuppressWildcards Initializer> } // :feature:startup-api module interface Initializer { operator fun invoke() }
  165. Data, Common, Feature . , . Version Catalog, Convention Plugins

    compileOnly + stub , fl avor . (ex. BuildCon fi g) -api, -impl , . , , runtimeOnly , app . . . , Con fl ict
  166. Dagger Hilt Hilt . @HiltAndroidApp class ExampleApplication : Application() {

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

    @Inject lateinit var bar: Bar } @Module @InstallIn(SingletonComponent::class) object FooModule { @Provides fun provideBar(): Bar = Bar() }
  168. @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 - ੄ઓࢿ ஶప੉ցܳ ࢤࢿೠ׮.
  169. Dagger Hilt (2) . @HiltAndroidApp class ExampleApplication : Application() {

    @Inject lateinit var bar: Bar } @Module @InstallIn(SingletonComponent::class) object FooModule { @Provides fun provideBar(): Bar = Bar() }
  170. ࢶ঱ೠ 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 { } }
  171. @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()); } }
  172. 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
  173. @HiltAndroidApp class ExampleApplication : Application() { @Inject lateinit var bar:

    Bar } = @HiltAndroidApp class ExampleApplication : Hilt_ExampleApplication() { @Inject lateinit var bar: Bar } ߄੉౟௏٘ܳ ߸ജೞৈ, ࠗݽ ௿ېझܳ ߸҃ೠ׮. (Gradle Plugin)
  174. 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ী ੽Ӕೞৈ, ੄ઓࢿ ઱ੑਸ ਃ୒ೠ׮.
  175. 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) { } }
  176. 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 ௿ېझܳ ా೧, উ٘۽੉٘ ௿ېझী ੄ઓࢿ੉ ઱ੑػ׮.
  177. Dagger Hilt Dagger Hilt . ( ) Link: h tt

    ps://youtu.be/iE_2llWUI6A
  178. Dagger Hilt . (KAPT/KSP) Gradle Plugin @AndroidEntryPoint Hilt Base .

    , Compiler . Hilt Dagger , Compiler . Factory Injector I/O . , . .
  179. Dagger Hilt , -impl . :data-impl :app :feature:search-impl :feature-common :feature:detail-impl

    :data-api :feature:search-api :feature:detail-api runtimeOnly runtimeOnly
  180. Dagger Hilt , @Module . :data-impl :app :feature:search-impl :feature-common :feature:detail-impl

    :data-api :feature:search-api :feature:detail-api runtimeOnly runtimeOnly @Module @Module @Module
  181. Dagger Hilt , . hilt_metadata :f:search-impl :f:detail-impl :data:impl @Metadata @Metadata

    @Metadata @InstallIn @InstallIn @InstallIn @Generated("dagger.hilt") interface MyApp_HiltComponents { @Component(modules = [ FeatureSearchModule::class, FeatureDetailModule::class, ... ]) interface SingletonC } DataModule::class,
  182. Android ߂ Java ਊ ੄ઓࢿ ઱ੑ ೐ۨ੐ਕ௼. ஹ౵ੌ ఋ੐ী ࣗझ௏٘

    ࢤࢿ. Dependency Injection ಁఢ. https://github.com/google/dagger Dagger ӝ߈ Android ੄ઓࢿ ઱ੑ ೐ۨ੐ਕ௼. ؀ࠗ࠙੄ Dagger ࢚ਊҳ ઁѢ. Dependency Injection ಁఢ. https://github.com/google/dagger Dagger Hilt 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 …
  183. Anvil Dagger Kotlin Anvil 2020 , Dagger KAPT . KAPT

    Kotlin Java Stub javac Annotation Processor , . Anvil Kotlin Compiler Plugin . Dagger Factory Kotlin , KAPT Java Stub . Dagger @Component / (IR) . @ContributesTo, @ContributesBinding , . (Aggregation) KAPT ,
  184. @Scope @Documented @Retention(RUNTIME) public @interface Singleton {} @Singleton @DefineComponent public

    interface SingletonComponent {} → (Hilt) ޷ܻ ੿੄ػ Scope // -------------------------------------------------------------------------------- abstract class AppScope private constructor() → (Anvil) Scope ࣻز ࢤࢿ Anvil਷ ೙ਃೠ Scope݅ ૒੽ ੿੄ೠ׮.
  185. @Module @InstallIn(SingletonComponent::class) object BarModule { @Provides fun provideBar(): Bar =

    Bar() } // -------------------------------------------------------------------------------- @Module @ContributesTo(AppScope::class) object BarModule { @Provides fun provideBar(): Bar = Bar() } Providesܳ ਤೠ Module ੿੄ח ࠺तೞ׮.
  186. @Module @InstallIn(SingletonComponent::class) interface FooModule { @Binds fun bindsFoo(impl: FooImpl): Foo

    } class FooImpl @Inject constructor() : Foo { ... } // -------------------------------------------------------------------------------- @ContributesBinding(AppScope::class) class FooImpl @Inject constructor() : Foo { ... } Anvil਷ Bindingਸ ਤೠ Module ౵ੌ ੗୓о ࠛ೙ਃೞ׮.
  187. @AndroidEntryPoint class HomeActivity : ComponentActivity() { @Inject lateinit var bar:

    Bar } → Hilt_HomeActivity.java ࢤࢿ → HomeActivity_GeneratedInjector.java ࢤࢿ → HomeActivity_MembersInjector.java ࢤࢿ // -------------------------------------------------------------------------------- class HomeActivity : ComponentActivity() { @Inject lateinit var bar: Bar override fun onCreate(savedInstanceState: Bundle?) { appComponent.inject(this) super.onCreate(savedInstanceState) } } → HomeActivity_MembersInjector.java ࢤࢿ Anvil਷ Hilt ؀࠺ ࢤࢿغח ౵ੌ ࣻо ௼ѱ ઴যٚ׮.
  188. @AndroidEntryPoint class HomeActivity : ComponentActivity() { @Inject lateinit var bar:

    Bar } → Hilt_HomeActivity.java ࢤࢿ → HomeActivity_GeneratedInjector.java ࢤࢿ → HomeActivity_MembersInjector.java ࢤࢿ // -------------------------------------------------------------------------------- class HomeActivity : ComponentActivity() { @Inject lateinit var bar: Bar override fun onCreate(savedInstanceState: Bundle?) { appComponent.inject(this) super.onCreate(savedInstanceState) } } → HomeActivity_MembersInjector.java ࢤࢿ Anvil਷ Hilt୊ۢ Base ௿ېझܳ ߄Բח ߄੉౟௏٘ ߸ജ੉ হ׮.
  189. SingletonC ȍȇȇ ServiceC └── ActivityRetainedC └── ActivityC ȍȇȇ ViewModelC ȍȇȇ

    ViewC ȍȇȇ ComposableC └── FragmentC └── ViewWithFragmentC → (Hilt) 8ѐ ஹನք౟ ੗ز ࢤࢿ // -------------------------------------------------------------------------------- @MergeComponent(AppScope::class) interface AppComponent → (Anvil) ஹನք౟ ࣻز ࢤࢿ Anvil਷ ೙ਃೠ ஹನք౟ܳ ૒੽ ੿੄ೞৈ, ࢤࢿغח ௏٘о ؀಩ ઴যٚ׮.
  190. @HiltAndroidApp class ExampleApplication : Application() { ... } → (Hilt)

    ੄ઓࢿ ஶప੉ց ੗ز ࢤࢿ // -------------------------------------------------------------------------------- class ExampleApplication : Application() { val component by lazy { DaggerAppComponent.factory().create(this) } ... } → (Anvil) ੄ઓࢿ ஶప੉ց ࣻز ࢤࢿ Anvil਷ Hilt୊ۢ Base ௿ېझܳ ߄Բח ߄੉౟௏٘ ߸ജ੉ হ׮.
  191. Dagger Hilt Dagger Hilt KAPT/KSP . Gradle Plugin . :data-impl

    :app :feature:search-impl :feature-common :feature:detail-impl :data-api :feature:search-api :feature:detail-api Hilt @Module (KAPT/KSP) Hilt @Module (KAPT/KSP) (KAPT/KSP) Hilt @Module Hilt (KAPT/KSP)
  192. Anvil Anvil KCP Dagger Module Factory, Hint . Hint @MergeComponent

    Dagger @Component . Dagger . (KAPT) :data-impl :app :feature:search-impl :feature-common :feature:detail-impl :data-api :feature:search-api :feature:detail-api Anvil @Module (KCP) Anvil @Module (KCP) (KCP) Anvil @Module Anvil @MergeComponent (KCP) + Dagger (KAPT)
  193. Anvil Anvil . class ExampleApplication : Application() { @Inject lateinit

    var foo: Foo } @ContributesBinding(AppScope::class) class FooImpl @Inject constructor() : Foo { ... }
  194. Anvil (1) . // :core:di module abstract class AppScope private

    constructor() // :feature:foo-impl module @ContributesBinding(AppScope::class) class FooImpl @Inject constructor() : Foo { ... } // :app module @Singleton @MergeComponent(AppScope::class) interface AppComponent { ... }
  195. // Hint ݫఋؘ੉ఠ public val io_github_fornewid_feature_foo_impl_FooImpl_reference: KClass<FooImpl> = FooImpl::class public

    val io_github_fornewid_feature_foo_impl_FooImpl_scope0: KClass<AppScope> = AppScope::class // Factory ௿ېझ public object FooImpl_Factory : Factory<FooImpl> { override fun `get`(): FooImpl = newInstance() @JvmStatic public fun create(): FooImpl_Factory = this @JvmStatic public fun newInstance(): FooImpl = FooImpl() } Hint ౵ੌҗ Factoryܳ ࢤࢿೠ׮.
  196. // о࢚ ߄ੋ٬ ݽٕ ࢤࢿ @Module @ContributesTo(AppScope::class) public abstract class

    AppComponentAnvilModule { @Binds public abstract fun bindFoo(fooImpl: FooImpl): Foo } // ߄੉౟௏٘ܳ ߸ઑೞৈ, @MergeComponentо ࣽࣻ Dagger @Component۽ ஖ജ @Singleton() @MergeComponent(scope = AppScope.class) @Component(modules = {AppComponentAnvilModule.class}) @kotlin.Metadata(...) public abstract interface AppComponent { ... } IRਸ ૒੽ ઑ੘ೞৈ ࠙࢑ػ ௏٘ܳ ೞա۽ ೤஘׮.
  197. Anvil (2) . // :app module @Singleton @MergeComponent(AppScope::class) interface AppComponent

    { fun inject(application: ExampleApplication) @Component.Factory interface Factory { fun create(@BindsInstance application: Application): AppComponent } }
  198. @Singleton() @MergeComponent(scope = AppScope.class) @Component(modules = {AppComponentAnvilModule.class}) @kotlin.Metadata(...) public abstract

    interface AppComponent { public abstract void inject(@NotNull() ExampleApplication application); @dagger.Component.Factory() @kotlin.Metadata(...) public static abstract interface Factory { @NotNull() public abstract AppComponent create( @BindsInstance() @NotNull() Application application ); } } Anvil੉ Hintܳ ӝ߈ਵ۽ Dagger @Componentܳ ҳࢿೠ׮.
  199. @DaggerGenerated @Generated(...) public final class DaggerAppComponent { public static AppComponent.Factory

    factory() { return new Factory(); } private static final class Factory implements AppComponent.Factory { @Override public AppComponent create(Application application) { Preconditions.checkNotNull(application); return new AppComponentImpl(application); } } private static final class AppComponentImpl implements AppComponent { private final AppComponentImpl appComponentImpl = this; private AppComponentImpl(Application applicationParam) {} @Override public void inject(ExampleApplication application) {} } } Daggerо ୭ઙ ஶప੉ցܳ ࢤࢿೠ׮.
  200. Anvil (3) . // :app module class ExampleApplication : Application()

    { @Inject lateinit var foo: Foo val appComponent by lazy { DaggerAppComponent.factory().create(this) } override fun onCreate() { super.onCreate() appComponent.inject(this) } }
  201. // Generated by Anvil. public class ExampleApplication_MembersInjector( private val foo:

    Provider<Foo>, ) : MembersInjector<ExampleApplication> { override fun injectMembers(instance: ExampleApplication) { ExampleApplication_MembersInjector.injectFoo(instance, foo.get()) } public companion object { @JvmStatic public fun create(foo: Provider<Foo>): MembersInjector<ExampleApplication> = ExampleApplication_MembersInjector(foo) @JvmStatic @InjectedFieldSignature("io.github.fornewid.dagger.hilt.example.ExampleApplication.foo") public fun injectFoo(instance: ExampleApplication, foo: Foo) { instance.foo = foo } } } Anvil੉ Injectorܳ ࢤࢿೠ׮.
  202. @DaggerGenerated @Generated(...) public final class DaggerAppComponent { ... private static

    final class AppComponentImpl implements AppComponent { private final AppComponentImpl appComponentImpl = this; private AppComponentImpl(Application applicationParam) {} @Override public void inject(ExampleApplication application) { injectExampleApplication(application); } private ExampleApplication injectExampleApplication(ExampleApplication instance) { ExampleApplication_MembersInjector.injectFoo(instance, new FooImpl()); return instance; } } } Daggerо ୭ઙ ஶప੉ցী Injectorо ನೣػ׮.
  203. Anvil vs Hilt Anvil KCP , KAPT . @ContributesTo ,

    @MergeComponent Dagger @Component . Dagger . (KAPT) Dagger Hilt KAPT, KSP . @AndroidEntryPoint, @InstallIn , Dagger @Component . Dagger . (KAPT, KSP)
  204. Anvil K2 Kotlin Compiler Plugin API . K1 K2 .

    KAPT Factory, Hint IR , KAPT/KSP . app KAPT . (Dagger) Hint I/O , anvil.hint Hint . app Hint .
  205. Android ߂ Java ਊ ੄ઓࢿ ઱ੑ ೐ۨ੐ਕ௼. ஹ౵ੌ ఋ੐ী ࣗझ௏٘

    ࢤࢿ. Dependency Injection ಁఢ. https://github.com/google/dagger Dagger ӝ߈ Android ੄ઓࢿ ઱ੑ ೐ۨ੐ਕ௼. ؀ࠗ࠙੄ Dagger ࢚ਊҳ ઁѢ. Dependency Injection ಁఢ. https://github.com/google/dagger Dagger Hilt 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 Metro Kotlin ஹ౵ੌ۞ ೒۞Ӓੋਸ ӝ߈ਵ۽ ೞח Kotlin ਊ ੄ઓࢿ ઱ੑ ೐ۨ੐ਕ௼. KMP ૑ਗ. ஹ౵ੌ ఋ੐ী ੄ઓࢿ Ӓې೐ ਬബࢿ Ѩࢎ. https://github.com/ZacSweers/metro
  206. Metro Dagger, Anvil, kotlin-inject Kotlin DI (KAPT/KSP) , Kotlin (FIR/IR

    ) . Kotlin , . Anvil (Aggregation) , . Dagger Anvil . KAPT/KSP ,
  207. @Scope @Documented @Retention(RUNTIME) public @interface Singleton {} @Singleton @DefineComponent public

    interface SingletonComponent {} → (Hilt) ޷ܻ ੿੄ػ Scope // -------------------------------------------------------------------------------- abstract class AppScope private constructor() → (Metro) Scope ࣻز ࢤࢿ Metroب ೙ਃೠ Scopeਸ ૒੽ ੿੄ೠ׮.
  208. @Module @InstallIn(SingletonComponent::class) object BarModule { @Provides fun provideBar(): Bar =

    Bar() } // -------------------------------------------------------------------------------- @ContributesTo(AppScope::class) interface BarModule { @Provides fun provideBar(): Bar = Bar() } → (Metro) @Module য֢ప੉࣌ ઁѢ Providesܳ ਤೠ ੿੄ח ࠺तೞ׮.
  209. @Module @InstallIn(SingletonComponent::class) interface FooModule { @Binds fun bindsFoo(impl: FooImpl): Foo

    } class FooImpl @Inject constructor() : Foo { ... } // -------------------------------------------------------------------------------- @ContributesBinding(AppScope::class) @Inject class FooImpl : Foo { ... } Metroب Bindingਸ ਤೠ Module ౵ੌ ੗୓о ࠛ೙ਃೞ׮.
  210. SingletonC ȍȇȇ ServiceC └── ActivityRetainedC └── ActivityC ȍȇȇ ViewModelC ȍȇȇ

    ViewC ȍȇȇ ComposableC └── FragmentC └── ViewWithFragmentC → (Hilt) 8ѐ ஹನք౟ ੗ز ࢤࢿ // -------------------------------------------------------------------------------- @DependencyGraph(AppScope::class) interface AppGraph { ... } → (Metro) ੄ઓࢿ Ӓې೐ ࣻز ੿੄ Metroח ੄ઓࢿ Ӓې೐ܳ ૒੽ ੿੄೧ঠ ೠ׮.
  211. @HiltAndroidApp class ExampleApplication : Application() { ... } → (Hilt)

    ੄ઓࢿ ஶప੉ց ੗ز ࢤࢿ // -------------------------------------------------------------------------------- class ExampleApplication : Application(), AppGraphProvider { override val appGraph: AppGraph by lazy { createGraphFactory<AppGraph.Factory>().create(this) } } → (Metro) ੄ઓࢿ Ӓې೐ ࣻز ࢤࢿ ӒܻҊ Applicationীࢲ ੄ઓࢿ Ӓې೐ܳ ૒੽ ࢤࢿ೧ঠ ೠ׮.
  212. @AndroidEntryPoint class HomeActivity : ComponentActivity() { @Inject lateinit var bar:

    Bar } → Hilt_HomeActivity.java ࢤࢿ → HomeActivity_GeneratedInjector.java ࢤࢿ → HomeActivity_MembersInjector.java ࢤࢿ // -------------------------------------------------------------------------------- class HomeActivity : ComponentActivity() { private val appGraph by lazy { appGraph<AppGraph>() } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val bar: Bar = appGraph.bar } } inline fun <reified T> Context.appGraph(): T { return (applicationContext as ExampleApplication).appGraph as T } Metroח ೙٘ ઱ੑ੉ হҊ, ੄ઓࢿ Ӓې೐ী ૒੽ ੽Ӕ೧ঠ ೠ׮.
  213. Metro Metro KCP FIR/IR , . Hilt Anvil . :data-impl

    :app :feature:search-impl :feature-common :feature:detail-impl :data-api :feature:search-api :feature:detail-api Metro .class (KCP) Metro .class (KCP) (KCP) Metro .class Metro .class (KCP)
  214. Metro Build Pipeline Metro Kotlin FIR, IR . binary files

    (.class) source files (.kt) Parse/PSI FIR Frontend Lowering IR Backend fir2ir Declaration ࢤࢿ Supertype ୶о Status ߸ജ Checker Factory ࢤࢿ Graph ҳഅ createGraph ஖ജ
  215. Metro Metro . class ExampleApplication : Application() { override fun

    onCreate() { super.onCreate() val foo: Foo = appGraph.foo } } @ContributesBinding(AppScope::class) @Inject class FooImpl : Foo { ... }
  216. Metro abstract class AppScope private constructor() @ContributesBinding(AppScope::class) @Inject class FooImpl

    : Foo { ... } @DependencyGraph(AppScope::class) interface AppGraph { val foo: Foo } class ExampleApplication : Application() { override val appGraph: AppGraph by lazy { createGraph<AppGraph>() } }
  217. FIR: Declaration // Contribution interfaces ࢤࢿ // FooImpl$MetroContributionToAppScope.class public interface

    FooImpl$MetroContributionToAppScope { Foo bindsAsFoo(FooImpl contributed); // FooImpl → Foo ߄ੋ٬ ੿ࠁ } // Hint ࢤࢿ // metro/hints/IoGithubFornewidFeatureFooImplFooImplAppScopeKt.class public final class metro.hints.IoGithubFornewidFeatureFooImplFooImplAppScopeKt { public static final void AppScope(FooImpl contributed) { throw new IllegalStateException("Never called"); } // ࠄޙ਷ ੄޷ হ਺. ೣࣻ दӒפ୊৬ Kotlin Metadata݅ ࢎਊؽ. // app ݽٕ ஹ౵ੌ द, ஹ౵ੌ۞о ੉޷ ݫݽܻী ۽٘ೠ ੉ ੿ࠁܳ // FirSessionীࢲ ௪ܻೞৈ "FooImpl੉ AppScopeী ӝৈೠ׮"ܳ ౵ঈೣ. }
  218. FIR: Supertype // খীࢲ ࢤࢿೠ ੋఠಕ੉झܳ AppGraphী ઱ੑ // AppGraph.class

    public interface AppGraph extends FooImpl$MetroContributionToAppScope { Foo getFoo(); }
  219. FIR: Status // Declaration੄ visibility ١ Statusܳ ઑ੿ೠ׮. // ৘ܳ

    ٜয, @Provides privateਵ۽ ࢶ঱غয ੓যب, AppGraph$Implীࢲ ੽Ӕೡ ࣻ ੓ب۾ оदࢿਸ ઑ੿ೠ׮. @ContributesTo(AppScope::class) interface BarModule { @Provides private fun providesBar(): Bar = BarImpl() // private → internal۽ ઑ੿ } // Kotlin ஹ౵ੌ۞ীࢲ ݽٚ ࢶ঱(௿ېझ, ೣࣻ, ೐۽ಌ౭)਷ Statusܳ ыҊ ੓׮: FirDeclarationStatus { visibility: Visibility — PUBLIC, PRIVATE, INTERNAL, PROTECTED modality: Modality — FINAL, OPEN, ABSTRACT, SEALED isExpect: Boolean — expect ࢶ঱ੋ૑ isActual: Boolean — actual ࢶ঱ੋ૑ isOverride: Boolean — overrideੋ૑ isInline: Boolean — inline funੋ૑ isSuspend: Boolean — suspend funੋ૑ isConst: Boolean — const valੋ૑ isLateInit: Boolean — lateinit varੋ૑ ...
  220. FIR: Checker // য֢ప੉࣌ ਬബࢿਸ Ѩࢎೠ׮. ઱ਃ Checker: DependencyGraphChecker —

    @DependencyGraphо interfaceੋ૑, ࢤࢿ੗ ౵ۄ޷ఠ হח૑ InjectConstructorChecker — @Inject ௿ېझо abstractо ইצ૑, ઺ࠂ @Inject হח૑ BindingContainerCallableChecker — @Provides ೣࣻ੄ ߈ജ ఋੑ੉ ਬബೠ૑ CreateGraphChecker — createGraph()੄ ఋੑ ੋ੗ী @DependencyGraphо ੓ח૑ AggregationChecker — @ContributesBinding ௿ېझо ৢ߄ܲ ഋకੋ૑ AssistedInjectChecker — @AssistedFactory੄ ౵ۄ޷ఠо ݒடغח૑ MembersInjectChecker — ݯߡ ઱ੑ੉ regular classীࢲ݅ ࢎਊغח૑ MultibindsChecker — @IntoMap, @IntoSet ١੉ ৢ߄ܰѱ ࢎਊغח૑ ... ৻ 8ѐ → ਤ߈ द IDEী ૊द ࡈр઴ ಴द (࠽٘ प೯ ੹ী ഛੋ оמ) → KSPח ࠽٘ܳ ج۰ঠ য়ܨܳ ঌ ࣻ ੓૑݅, Metroח ௏٘ ੘ࢿ ૊द ೖ٘ߔ
  221. IR: Factory // FooImpl$MetroFactory.class ࢤࢿ public final class FooImpl$MetroFactory implements

    Factory<FooImpl> { public static final FooImpl$MetroFactory INSTANCE; // यӖఢ public final FooImpl newInstance() { return new FooImpl(); // ૒੽ ࢤࢿ੗ ഐ୹ } }
  222. IR: // AppGraph$Impl.class ࢤࢿ public final class AppGraph$Impl implements AppGraph

    { // unscoped → ݒߣ new۽ ૒੽ ࢤࢿ public Foo getFoo() { return new FooImpl(); } }
  223. IR: // ѐߊ੗о ੘ࢿೠ ௏٘ val appGraph: AppGraph by lazy

    { createGraph<AppGraph>() } // Metro ղࠗ ௏٘ public inline fun <reified T : Any> createGraph(): T { throw UnsupportedOperationException("Implemented by the compiler") } // IR ஖ജ റ private static final AppGraph appGraph_delegate$lambda$0() { return new AppGraph$Impl(); // createGraphо ૒੽ ࢤࢿ੗ ഐ୹۽ ஖ജؽ }
  224. Metro . class ExampleApplication : Application() { override val appGraph:

    AppGraph by lazy { createGraph<AppGraph>() } override fun onCreate() { super.onCreate() val foo: Foo = appGraph.foo } }
  225. Hilt: [kotlinc] [KSP:Hilt] [KSP:Dagger] [javac] [ ] 5 Anvil: [kotlinc

    + Anvil KCP] [KAPT:Dagger] [javac] 3 Metro: [kotlinc + Metro KCP] 1 Metro AppGraph$Impl.class ExampleApplication Foo
  226. Anvil Metro KSP/KAPT , 100% Compiler Plugin . Hint ,

    I/O . .class , . @Module @ContributesBinding , . KSP , Metro FIR Checker . (IDE ) Kotlin Multiplatform .
  227. Metro Kotlin Version Coupling JetBrains Kotlin API(FIR, IR) , Kotlin

    . Metro Kotlin . Kotlin 2.0 (K2 ) . 0.x ( 0.13.2) API . , . Kotlin , . .
  228. Migration Metro Dagger, Anvil, kotlin-inject . . , Dagger Hilt

    Hilt Metro . ( ...) Dagger Hilt Anvil Metro Dagger @Deprecated
  229. !