2023년 9월 12일 (화) 드로이드나이츠 2023 행사에서의 발표자료입니다. https://festa.io/events/3635
Dagger Hilt۽ઓࢿ ੑࠗఠ ݣ౭ݽٕചөSUNGYONG AN / NAVER WEBTOON
View Slide
Sungyong AnNAVER WEBTOONAndroid GDE@fornewidLink: https://github.com/fornewid
“যڃ ղਊਸ ܖաਃ?”🤔Intro
Dependency Injectionઓࢿ ੑ(DI) ೞա ёо ܲ ё ઓࢿਸ ઁҕೞח ӝߨ.ઓࢿ ੑ بח ё ࢤࢿҗ ࢎਊ ҙबਸ ܻ࠙ೞח Ѫ.DI ਗਸ ٮܰݶ ഴܯೠ জ ইఃఫܳ ਤೠ షܳ ݃۲ೡ ࣻ .• ٘ ࢎਊ оמ• ܻಂష݂ ಞࢿ• పझ ಞࢿLink: https://en.wikipedia.org/wiki/Dependency_injection
// Without Dependency Injectionclass Car {private val engine: Engine = Engine() // construct + usefun start() {engine.start()}}fun main(args: Array) {val car = Car()car.start()}CarEngine
// Dependency Injection (Constructor Injection)class Car(private val engine: Engine // use) {fun start() {engine.start()}}fun main(args: Array) {val engine = Engine() // constructval car = Car(engine)car.start()}CarEngine
// Dependency Injection (Field Injection)class Car {lateinit var engine: Engine // usefun start() {engine.start()}}fun main(args: Array) {val car = Car()car.engine = Engine() // constructcar.start()}CarEngine
Dagger HiltAndroidীࢲ ઓࢿਸ ੑೞח ݾਵ۽ ӂೞח ۄ࠳۞ܻ.۽ં ݽٚ Android ېझী ஶపցܳ ઁҕೞҊ, ࣻݺ ӝܳ زਵ۽ ҙܻ೧ળ.(Application, Activity, Service, BroadcastReceiver, ViewModel)Hiltח Dagger ӝ߈ ۄ࠳۞ܻ۽, ஹੌ ఋী ઓࢿ Ӓېܳ Ѩૐೡ ࣻ .ੌࠗ Jetpack ېझীب ઓࢿਸ ੑೡ ࣻ ب۾, Hilt ഛ ۄ࠳۞ܻب ઁҕػ.(WorkManager, Navigation)Link: https://developer.android.com/training/dependency-injection#hilt
@Module@InstallIn(SingletonComponent::class)class EngineModule {@Provides // constructfun providesEngine(): Engine = Engine()}Link: https://dagger.dev/hilt/quick-star@Provides ١ਸ ਊೞৈ, ઓࢿਸ ઁҕೡ ࣻ .Engine
@Module@InstallIn(SingletonComponent::class)class EngineModule {@Provides // constructfun providesEngine(): Engine = Engine()}// Dependency Injection (Constructor Injection)class Car @Inject constructor( // useprivate val engine: Engine,)Link: https://dagger.dev/hilt/quick-star@Injectܳ ਊೞৈ, ઓࢿਸ ېझ ࢤࢿী ੑೡ ࣻ .CarEngine
@Module@InstallIn(SingletonComponent::class)class EngineModule {@Provides // constructfun providesEngine(): Engine = Engine()}// Dependency Injection (Constructor Injection)class Car @Inject constructor( // useprivate val engine: Engine,)@AndroidEntryPointclass ExampleActivity : ComponentActivity() {// Dependency Injection (Field Injection)@Inject // uselateinit var car: Car}Link: https://dagger.dev/hilt/quick-starAndroid ېझח ࢤࢿо ইצ, ٘ী ઓࢿਸ ੑೠ.CarExampleActivityEngine
@Module@InstallIn(SingletonComponent::class)class EngineModule {@Providesfun providesEngine(): Engine = Engine()}// Dependency Injection (Constructor Injection)class Car @Inject constructor(private val engine: Engine,)@AndroidEntryPointclass ExampleActivity : ComponentActivity() {// Dependency Injection (Field Injection)@Injectlateinit var car: Car}= public @interface Module { ... }= public @interface InstallIn { ... }= public @interface Provides {}= public @interface Inject {}= public @interface AndroidEntryPoint { ... }= public @interface Inject {}Link: https://en.wikipedia.org/wiki/Java_annotationӒؘ۠ Annotationਸ ಝࠁݶ, ઓࢿ ੑҗ ҙ۲ػ ٘о হ???
// build.gradledependencies {implementation 'com.google.dagger:hilt-android:2.48'// For JavaannotationProcessor ‘com.google.dagger:hilt-compiler:2.48'// For Kotlinkapt 'com.google.dagger:hilt-compiler:2.48'// orksp 'com.google.dagger:hilt-compiler:2.48'}Link: https://dagger.dev/hilt/gradle-setup⚠ KSPח Dagger Hilt 2.48 ߡࠗఠ ਗؾפ! (alpha)Hiltо Annotationਸ ӝ߈ਵ۽, ઓࢿ ੑী ਃೠ ٘ܳ ٜ݅যળ.There is no magic!
“Dagger Hiltо ࢤࢿೞח ٘ܳ ࠙ࢳೞৈ, Hiltо উ٘۽٘ জী ઓࢿਸ ੑೞח җਸ ೧೧ ࠁ.”Goal+ “ݣ౭ ݽٕীࢲ ࢎਊ ߑߨਸ Ҋ೧ ࠁ.”⚠ ठۄ٘ ٘ח Dagger Hilt 2.48 ߡਸ ӝળਵ۽ ࢿغणפ.
Dagger Hilt ղࠗ٘ ࠙ࢳ.
Start!@HiltAndroidAppclass ExampleApplication : Application() {@Inject lateinit var bar: Bar}@AndroidEntryPointclass ExampleActivity : ComponentActivity() {@Inject lateinit var bar: Bar}@Module@InstallIn(SingletonComponent::class)internal object FooModule {@Providesfun provideBar(): Bar = Bar()}Link: https://dagger.dev/hilt/quick-starExampleApplication_HiltComponents.java-> Hilt_ExampleApplication.javaExampleApplication_GeneratedInjector.javaExampleApplication_MembersInjector.java-> Hilt_ExampleActivity.javaExampleActivity_GeneratedInjector.javaExampleActivity_MembersInjector.java-> HiltWrapper_FooModule.javaFooModule_ProvideBarFactory.javaজ ݽٕ build ಫ؊ী Java ੌٜ ࢤࢿػ.
Start!@HiltAndroidAppclass ExampleApplication : Application() {@Inject lateinit var bar: Bar}@AndroidEntryPointclass ExampleActivity : ComponentActivity() {@Inject lateinit var bar: Bar}@Module@InstallIn(SingletonComponent::class)internal object FooModule {@Providesfun provideBar(): Bar = Bar()}Link: https://dagger.dev/hilt/quick-starExampleApplication_HiltComponents.java-> Hilt_ExampleApplication.javaExampleApplication_GeneratedInjector.javaExampleApplication_MembersInjector.java-> Hilt_ExampleActivity.javaExampleActivity_GeneratedInjector.javaExampleActivity_MembersInjector.java-> HiltWrapper_FooModule.javaFooModule_ProvideBarFactory.javaӏ ࠁաਃ?
public final class ExampleApplication_HiltComponents {@Component(modules = { ActivityRetainedCBuilderModule.class, ... })@Singletonpublic abstract static class SingletonC implements ...,SingletonComponent, ExampleApplication_GeneratedInjector {}@Subcomponent(modules = { ActivityCBuilderModule.class, ... })@ActivityRetainedScopedpublic abstract static class ActivityRetainedC implements ..., ActivityRetainedComponent {@Subcomponent.Builderabstract interface Builder extends ActivityRetainedComponentBuilder {}}@Subcomponent(modules = { FragmentCBuilderModule.class, ... })@ActivityScopedpublic abstract static class ActivityC implements ...,ActivityComponent, ExampleActivity_GeneratedInjector {@Subcomponent.Builderabstract interface Builder extends ActivityComponentBuilder {}}...}ࢤࢿػ ٘ীب ৈ Annotation ???
Component generationLink: https://medium.com/androiddevelopers/mad-skills-series-hilt-under-the-hood-9d89ee227059Hiltо Dagger ٘ܳ ࢤࢿೞҊ աࢲ, Daggerо ୭ઙ ٘ܳ ࢤࢿೠ.
@HiltAndroidAppclass ExampleApplication : Application()// --------------------------------------------------------------------------------// Generated by Hiltpublic final class ExampleApplication_HiltComponents {@Component(modules = { ActivityRetainedCBuilderModule.class, ... })@Singletonpublic abstract static class SingletonC implements SingletonComponent {}...}// --------------------------------------------------------------------------------// Generated by Daggerpublic final class DaggerExampleApplication_HiltComponents_SingletonC {private static final class SingletonCImplextends ExampleApplication_HiltComponents.SingletonC {public void injectExampleApplication(ExampleApplication exampleApplication) {}}...}@HiltAndroidApp জ ઓࢿ Ӓېܳ ࢤࢿೞח ӝળ ػ.
BarOverviewExampleApplicationDaggerExampleApplication_HiltComponents_SingletonCExampleActivityFooModule
@HiltAndroidAppclass ExampleApplication : Application() {@Inject lateinit var bar: Bar}BarOverviewExampleApplicationDaggerExampleApplication_HiltComponents_SingletonCExampleActivityFooModule(1) ӝࠄ ࢤࢿغח ઓࢿ Ӓېܳ ಝࠁ.
Component hierarchySingletonComponentFragmentComponentViewWithFragmentComponentViewComponentActivityRetainedComponentActivityComponentServiceComponentViewModelComponent@Singleton@ActivityRetainedScoped@ServiceScoped@ViewModelScoped@FragmentScoped@ActivityScoped@ViewScoped@ViewScopedLink: https://developer.android.com/training/dependency-injection/hilt-android#component-hierarchyHiltо ӝࠄ ઁҕೞח Component৬ Scope.
@Scope@Documented@Retention(RUNTIME)public @interface Singleton {}@Singleton@DefineComponentpublic interface SingletonComponent {}
public final class ExampleApplication_HiltComponents {@Component(modules = {ApplicationContextModule.class,ActivityRetainedCBuilderModule.class,})@Singletonpublic abstract static class SingletonC implementsHiltWrapper_ActivityRetainedComponentManager_ActivityRetainedComponentBuilderEntryPoint,SingletonComponent,GeneratedComponent {}}
public final class DaggerExampleApplication_HiltComponents_SingletonC {public static Builder builder() {return new Builder();}public static final class Builder {public ExampleApplication_HiltComponents.SingletonC build() {return new SingletonCImpl();}}private static final class SingletonCImpl extends SingletonC {private final SingletonCImpl singletonCImpl = this;private SingletonCImpl() {}}}п Component݃ ۠ ېझо ࢤࢿػ.
HiltComponentsSingletonC(Impl)FragmentC(Impl)ViewWithFragmentC(Impl)ViewC(Impl)ActivityRetainedC(Impl)ActivityC(Impl)ServiceC(Impl)ViewModelC(Impl)@Singleton@ActivityRetainedScoped@ServiceScoped@ViewModelScoped@FragmentScoped@ActivityScoped@ViewScoped@ViewScopedп Component / Scopeী ೞח ېझ.
Component hierarchySingletonComponentFragmentComponentViewWithFragmentComponentViewComponentActivityRetainedComponentActivityComponentServiceComponentViewModelComponentLink: https://developer.android.com/training/dependency-injection/hilt-android#component-hierarchy@Inject࢚ਤ ஹನք ઓࢿਸ ೞਤী ੑೡ ࣻ Ҋ, ਵ۽ח ೡ ࣻ হ. যڌѱ???
DaggerExampleApplication_HiltComponents_SingletonCExampleApplication_HiltComponentsHiltComponentsSingletonCActivityRetainedCActivityCSingletonCImplActivityCImpl@Singleton@ActivityRetainedScoped@ActivityScoped@Module@ModuleActivityRetainedCImpl
public final class DaggerExampleApplication_HiltComponents_SingletonC {private static final class SingletonCImpl extends SingletonC {private SingletonCImpl() {}}private static final class ActivityRetainedCImpl extends ActivityRetainedC {private ActivityRetainedCImpl(SingletonCImpl singletonCImpl) { ... }}}
public final class DaggerExampleApplication_HiltComponents_SingletonC {private static final class SingletonCImpl extends SingletonC {private SingletonCImpl() {}}private static final class ActivityRetainedCImpl extends ActivityRetainedC {private ActivityRetainedCImpl(SingletonCImpl singletonCImpl) { ... }}private static final class ActivityCImpl extends ActivityC {private ActivityCImpl(SingletonCImpl singletonCImpl,ActivityRetainedCImpl activityRetainedCImpl,Activity activityParam) { ... }}}ೞਤ ஹನքח ࢚ਤ ஹನքী Ӕೡ ࣻ . ߈۽ח X.
@Module@InstallIn(SingletonComponent::class)object FooModule {@Providesfun provideBar(): Bar = Bar()}BarOverviewExampleApplicationDaggerExampleApplication_HiltComponents_SingletonCExampleActivity(2) ೠ ઓࢿ Ӓېী যڌѱ ୶оغח ಝࠁ.FooModule
@Module@InstallIn(SingletonComponent::class)object FooModule {@Providesfun provideBar(): Bar = Bar()}// --------------------------------------------------------------------------------public final class ExampleApplication_HiltComponents {@Component(modules = {ApplicationContextModule.class,ActivityRetainedCBuilderModule.class,FooModule.class,})@Singletonpublic abstract static class SingletonC implementsHiltWrapper_ActivityRetainedComponentManager_ActivityRetainedComponentBuilderEntryPoint,SingletonComponent,GeneratedComponent {}}ࢶೠ Componentী Module ୶оػ.
@Module@InstallIn(SingletonComponent::class)object FooModule {@Providesfun provideBar(): Bar = Bar()}// --------------------------------------------------------------------------------public final class FooModule_ProvideBarFactory implements Factory {public static Bar provideBar() {return Preconditions.checkNotNullFromProvides(FooModule.INSTANCE.provideBar());}}@Provides݃ ઓࢿਸ ઁҕೞח Factory ېझо ࢤࢿػ.
@HiltAndroidAppclass ExampleApplication : Application() {@Injectlateinit var bar: Bar}BarOverviewExampleApplicationDaggerExampleApplication_HiltComponents_SingletonCExampleActivityFooModule(3) উ٘۽٘ ېझী ੑೞח җਸ ಝࠁ.Hilt_ExampleApplication.javaExampleApplication_GeneratedInjector.javaExampleApplication_MembersInjector.java
ExampleApplication_GeneratedInjector.java@GeneratedEntryPoint@InstallIn(SingletonComponent.class)public interface ExampleApplication_GeneratedInjector {void injectExampleApplication(ExampleApplication exampleApplication);}// --------------------------------------------------------------------------------public final class ExampleApplication_HiltComponents {@Component(modules = { ... })@Singletonpublic abstract static class SingletonC implementsHiltWrapper_ActivityRetainedComponentManager_ActivityRetainedComponentBuilderEntryPoint,SingletonComponent,GeneratedComponent,ExampleApplication_GeneratedInjector {}}// --------------------------------------------------------------------------------public final class DaggerExampleApplication_HiltComponents_SingletonC {private static final class SingletonCImpl extends SingletonC {public void injectExampleApplication(ExampleApplication instance) {}}
ExampleApplication_MembersInjector.java@HiltAndroidAppclass ExampleApplication : Application() {@Inject lateinit var bar: Bar}// --------------------------------------------------------------------------------public final class ExampleApplication_MembersInjectorimplements MembersInjector {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 ېझח Componentী ୶оػ.
Hilt_ExampleApplication.java@HiltAndroidAppclass ExampleApplication : Application() {@Inject lateinit var bar: Bar}=@HiltAndroidAppclass ExampleApplication : Hilt_ExampleApplication() {@Inject lateinit var bar: Bar}߄٘ܳ ߸ജೞৈ, ࠗݽ ېझܳ ߸҃ೠ.
public abstract class Hilt_ExampleApplication extends Application {private boolean injected = false;@CallSuper@Overridepublic 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ী Ӕೞৈ, ઓࢿ ੑਸ ਃೠ.
DaggerExampleApplication_HiltComponents_SingletonCSingletonCImplDependency injection flow (Application)FooModule_ProvideBarFactoryExampleApplication_MemeberInjectorExampleApplicationHilt_ExampleApplicationBarExampleApplication_GeneratedInjectorApplicationComponentManager۠ ܴਵ۽ ઓࢿ ੑػ.
DaggerExampleApplication_HiltComponents_SingletonC-CImplDependency injection flow (Android Classes)FooModule_ProvideBarFactory{CLASS}_MemeberInjector{CLASS}Hilt_{CLASS}Bar{CLASS}_GeneratedInjector-ComponentManagerܲ Android Classesب زੌೞ.
DaggerExampleApplication_HiltComponents_SingletonC-CImplDependency injection flow{CLASS}_MemeberInjector{CLASS}Hilt_{CLASS}Bar{CLASS}_GeneratedInjector-ComponentManagerઓࢿਸ ઁҕೞח ࠗ࠙ਸ ખ ؊ ಝࠁ.FooModule_ProvideBarFactory
@Module@InstallIn(SingletonComponent::class)object FooModule {@Providesfun provideBar(): Bar = Bar()}@ProvidesBarExampleApplicationDaggerExampleApplication_HiltComponents_SingletonCExampleActivityFooModule_ProvideBarFactory
@Module@InstallIn(SingletonComponent::class)object FooModule {@Providesfun provideBar(): Bar = Bar()}// --------------------------------------------------------------------------------public final class FooModule_ProvideBarFactory implements Factory {public static Bar provideBar() {return Preconditions.checkNotNullFromProvides(FooModule.INSTANCE.provideBar());}}// --------------------------------------------------------------------------------private static final class SingletonCImpl extends SingletonC {public void injectExampleApplication(ExampleApplication instance) {ExampleApplication_MembersInjector.injectBar(instance, FooModule_ProvideBarFactory.provideBar());}} @Providesח Factory ېझܳ ా೧ ઓࢿਸ ઁҕೠ.
class Bar @Inject constructor()@InjectBarExampleApplicationDaggerExampleApplication_HiltComponents_SingletonCExampleActivity
class Bar @Inject constructor()// --------------------------------------------------------------------------------private static final class SingletonCImpl extends SingletonC {public void injectExampleApplication(ExampleApplication instance) {ExampleApplication_MembersInjector.injectBar(instance, new Bar());}}@Injectח ߹ب ٘হ, ઓࢿਸ ߄۽ ઁҕೠ.
interface Barclass BarImpl @Inject constructor(): Bar@Module@InstallIn(SingletonComponent::class)interface FooModule {@Bindsfun bindBar(impl: BarImpl): Bar}@BindsBarImplExampleApplicationDaggerExampleApplication_HiltComponents_SingletonCExampleActivity
interface Barclass BarImpl @Inject constructor(): Bar@Module@InstallIn(SingletonComponent::class)interface FooModule {@Bindsfun bindBar(impl: BarImpl): Bar}// --------------------------------------------------------------------------------private static final class SingletonCImpl extends SingletonC {public void injectExampleApplication(ExampleApplication instance) {ExampleApplication_MembersInjector.injectBar(instance, new BarImpl());}}@Bindsܳ ೣԋ ࢎਊ೧ب زੌೞ.
@Singletonclass Bar @Inject constructor()ScopeBarExampleApplicationDaggerExampleApplication_HiltComponents_SingletonCExampleActivityDoubleCheck + SwitchingProvider
@Singletonclass Bar @Inject constructor()// --------------------------------------------------------------------------------private static final class SingletonCImpl extends SingletonC {private Provider barProvider;private SingletonCImpl() {this.barProvider = DoubleCheck.provider(new SwitchingProvider(this, 0));}public void injectExampleApplication(ExampleApplication instance) {ExampleApplication_MembersInjector.injectBar(instance, (Bar)this.barProvider.get());}private static final class SwitchingProvider implements Provider {public T get() {switch (this.id) {case 0: return new Bar();default: throw new AssertionError(this.id);}}}} Scopeܳ ࢶೞݶ, ೧ Componentী Providerܳ ࢤࢿೠ.
public final class DoubleCheck implements Provider, Lazy {public T get() {Object result = instance;if (result == UNINITIALIZED) {synchronized (this) {result = instance;if (result == UNINITIALIZED) {result = provider.get();instance = reentrantCheck(instance, result);provider = null;}}}return (T) result;}public static , T> Provider provider(P delegate) {return new DoubleCheck(delegate);}}DoubleCheckח ёܳ ೞա݅ ࢤࢿೠ.
Scope: Advancedprivate static final class SingletonCImpl extends SingletonC {private Provider barImplProvider = new SwitchingProvider(this, 0);private Provider bindBarProvider = DoubleCheck.provider(this.barImplProvider);public void injectExampleApplication(ExampleApplication instance) {ExampleApplication_MembersInjector.injectBar(instance, (Bar)this.bindBarProvider.get());}}interface Barclass BarImpl @Inject constructor(): BarScopeܳ ࢶೠ ਤী DoubleCheckо ࠢח.@Module@InstallIn(SingletonComponent::class)interface FooModule {@Singleton@Binds fun bindBar(impl: BarImpl): Bar}
Scope: Advancedprivate static final class SingletonCImpl extends SingletonC {private Provider barImplProvider = new SwitchingProvider(this, 0);private Provider bindBarProvider = DoubleCheck.provider(this.barImplProvider);private Provider bindBar2Provider = DoubleCheck.provider(this.barImplProvider);public void injectExampleApplication(ExampleApplication instance) {ExampleApplication_MembersInjector.injectBar(instance, (Bar)this.bindBarProvider.get());ExampleApplication_MembersInjector.injectBar2(instance, (Bar2)this.bindBar2Provider.get());}}interface Barinterface Bar2class BarImpl @Inject constructor(): Bar, Bar2interface FooModule {@Singleton@Binds fun bindBar(impl: BarImpl): Bar@Singleton@Binds fun bindBar2(impl: BarImpl): Bar2}, BarImpl ৈ۞ ߣ ࢤࢿؼ ࣻب .
Scope: Advancedprivate static final class SingletonCImpl extends SingletonC {private Provider barImplProvider = DoubleCheck.provider(new SwitchingProvider(this, 0));public void injectExampleApplication(ExampleApplication instance) {ExampleApplication_MembersInjector.injectBar(instance, (Bar)this.barImplProvider.get());ExampleApplication_MembersInjector.injectBar2(instance, (Bar2)this.barImplProvider.get());}}interface Barinterface Bar2@Singletonclass BarImpl @Inject constructor(): Bar@Module@InstallIn(SingletonComponent::class)interface FooModule {@Binds fun bindBar(impl: BarImpl): Bar@Binds fun bindBar2(impl: BarImpl): Bar2}Scopeܳ ࢶೞח ਤܳ ೞ!
DaggerExampleApplication_HiltComponents_SingletonC-CImplDependency injection flowFooModule_ProvideBarFactory{CLASS}_MemeberInjector{CLASS} Barઓࢿਸ ੑ߉ח ࠗ࠙ਸ ખ ؊ ಝࠁ.Hilt_{CLASS}-ComponentManager{CLASS}_GeneratedInjector
@Injectprivate static final class ActivityCImpl extends SingletonC {public void injectExampleActivity(ExampleActivity instance) {ExampleActivity_MembersInjector.injectBar(instance, new Bar());}}@AndroidEntryPointclass ExampleActivity : ComponentActivity() {@Injectlateinit var bar: Bar}
@Inject: Inheritanceprivate static final class ActivityCImpl extends SingletonC {public void injectExampleActivity(ExampleActivity instance) {BaseActivity_MembersInjector.injectBar(instance, new Bar());ExampleActivity_MembersInjector.injectBar(instance, new Bar());}}@AndroidEntryPointclass ExampleActivity : BaseActivity() {@Injectlateinit var bar: Bar}public abstract class BaseActivityextends ComponentActivity {@Inject Bar bar;}@Inject ݃ ࢲ۽ ܲ ёܳ ࢤࢿೠ.
Providerprivate static final class ActivityCImpl extends ActivityC {private Provider barProvider = new SwitchingProvider(..., 0);public void injectExampleActivity(ExampleActivity instance) {ExampleActivity_MembersInjector.injectBar(instance, this.barProvider);}}@AndroidEntryPointclass ExampleActivity : ComponentActivity() {@Injectlateinit var bar: Provider}get()ਸ ഐೡ ٸ݃, ࢤࢿೠ.fun doSomething() {bar.get().doSomething()}
Lazyprivate static final class ActivityCImpl extends ActivityC {private Provider barProvider = new SwitchingProvider(..., 0);public void injectExampleActivity(ExampleActivity instance) {ExampleActivity_MembersInjector.injectBar(instance, DoubleCheck.lazy(this.barProvider));}}@AndroidEntryPointclass ExampleActivity : ComponentActivity() {@Injectlateinit var bar: Lazy}get()ਸ ഐೞݶ, ୭ୡ ೠߣ݅ ࢤࢿೠ. Scope৬ ਬࢎೞ.fun doSomething() {bar.get().doSomething()}
public final class DoubleCheck implements Provider, Lazy {...public static , T> Provider provider(P delegate) {if (delegate instanceof DoubleCheck) {return delegate;}return new DoubleCheck(delegate);}public static , T> Lazy lazy(P provider) {if (provider instanceof Lazy) {final Lazy lazy = (Lazy) provider;return lazy;}return new DoubleCheck(provider);}}DoubleCheck.provider() ≈ DoubleCheck.lazy()
Lazy: Advancedprivate static final class ActivityCImpl extends ActivityC {private Provider barProvider = new SwitchingProvider(..., 0);public void injectExampleActivity(ExampleActivity instance) {ExampleActivity_MembersInjector.injectBar(instance, DoubleCheck.lazy(this.barProvider));ExampleActivity_MembersInjector.injectExampleUseCase(instance,new ExampleUseCase(DoubleCheck.lazy(this.barProvider)));}}@AndroidEntryPointclass ExampleActivity : ComponentActivity() {@Injectlateinit var bar: Lazy@Injectlateinit var useCase: ExampleUseCase}ೞ݅ @Inject ݃ ࢲ۽ ܲ ёܳ ࢤࢿೠ. , Barо ৈ۞ ߣ ࢤࢿؼ ࣻ .class ExampleUseCase @Inject constructor(private val bar: Lazy) { ... }
Scope + Providerprivate static final class ActivityCImpl extends ActivityC {private Provider barProvider = DoubleCheck.provider(new SwitchingProvider(..., 0));public void injectExampleActivity(ExampleActivity instance) {ExampleActivity_MembersInjector.injectBar(instance, this.barProvider);}}@AndroidEntryPointclass ExampleActivity : ComponentActivity() {@Injectlateinit var bar: Provider}ёܳ ೠߣ݅ ো ࢤࢿೞ۰ݶ, Lazyࠁח Scope + Providerܳ ࢎਊೞ.@ActivityScopedclass Bar @Inject constructor()
Scopeprivate static final class ActivityCImpl extends ActivityC {private Provider barProvider = DoubleCheck.provider(new SwitchingProvider(..., 0));public void injectExampleActivity(ExampleActivity instance) {ExampleActivity_MembersInjector.injectBar(instance, this.barProvider.get());}}@AndroidEntryPointclass ExampleActivity : ComponentActivity() {@Injectlateinit var bar: Bar}(ܻ݃ੋ٘) Scope݅ ೠ ҃ীח ࢤࢿೞৈ ੑೠ.@ActivityScopedclass Bar @Inject constructor()
EntryPointHiltо ਗೞ ঋח ېझী ઓࢿਸ ઁҕೞח ߑߨ (ex. ContentProvider)class Bar @Inject constructor()@EntryPoint@InstallIn(SingletonComponent::class)interface ExampleEntryPoint {fun bar(): Bar}val entryPoint = EntryPointAccessors.fromApplication(context = context,entryPoint = ExampleEntryPoint::class.java,)val bar: Bar = entryPoint.bar()
@EntryPoint@InstallIn(SingletonComponent::class)interface ExampleEntryPoint {fun bar(): Bar}// --------------------------------------------------------------------------------// Generated by Hiltpublic final class ExampleApplication_HiltComponents {@Component(modules = { ... })@Singletonpublic abstract static class SingletonCimplements SingletonComponent, GeneratedComponent, ExampleEntryPoint {}}// --------------------------------------------------------------------------------// Generated by Daggerpublic final class DaggerExampleApplication_HiltComponents_SingletonC {private static final class SingletonCImpl extends SingletonC {public Bar bar() { return new Bar(); }}...} (1) EntryPointо ઓࢿ Ӓېী ୶оػ.
val entryPoint = EntryPointAccessors.fromApplication(context = context,entryPoint = ExampleEntryPoint::class.java,)// --------------------------------------------------------------------------------object EntryPointAccessors {fun fromApplication(context: Context, entryPoint: Class): T =EntryPoints.get(Contexts.getApplication(context.applicationContext), entryPoint)}// --------------------------------------------------------------------------------public final class EntryPoints {public static T get(Object component, Class entryPoint) {if (component instanceof GeneratedComponent) {return entryPoint.cast(component);} else if (component instanceof GeneratedComponentManager) {return get(((GeneratedComponentManager>) component).generatedComponent(), entryPoint);} else {throw new IllegalStateException("...");}}} (2) Applicationਸ ఐ࢝ೞৈ, EntryPointо ҳഅػ Componentܳ оઉৡ.
val entryPoint = EntryPointAccessors.fromApplication(context = context,entryPoint = ExampleEntryPoint::class.java,)// --------------------------------------------------------------------------------object EntryPointAccessors {fun fromApplication(context: Context, entryPoint: Class): T =EntryPoints.get(Contexts.getApplication(context.applicationContext), entryPoint)}// --------------------------------------------------------------------------------public final class EntryPoints {public static T get(Object component, Class entryPoint) {if (component instanceof GeneratedComponent) {return entryPoint.cast(component);} else if (component instanceof GeneratedComponentManager) {return get(((GeneratedComponentManager>) component).generatedComponent(), entryPoint);} else {throw new IllegalStateException("...");}}} GeneratedComponentManager???
// Generated by Hiltpublic final class ExampleApplication_HiltComponents {@Component(modules = { ... })@Singletonpublic abstract static class SingletonCimplements SingletonComponent, GeneratedComponent, ExampleEntryPoint {}}// --------------------------------------------------------------------------------public abstract class Hilt_ExampleApplication extends Applicationimplements GeneratedComponentManager {private final ApplicationComponentManager componentManager = ...;public final Object generatedComponent() {return this.componentManager.generatedComponent();}}= Hilt_ExampleApplication
DaggerExampleApplication_HiltComponents_SingletonCSingletonCImplEntryPoint flowExampleEntryPointEntryPoints BarGeneratedComponentGeneratedComponentManagerܻೞݶ, ۠ ܴਵ۽ ઓࢿਸ оઉৡ.
EntryPointܳ ഝਊೞৈ, ઓࢿਸ ੑೞҊ .❏ ViewModel❏ WorkManager❏ NavigationJetpack ېझী ੑغח җ, “I/O Extended 2023 Seoul” ীࢲ ߊܐܳ ଵҊ೧ࣁਃ.Jetpack LibrariesLink: https://speakerdeck.com/fornewid/dagger-hiltro-yijonseong-juibhagi?slide=38
ݣ౭ݽٕীࢲ ઓࢿ ੑ.⚠ ਊয ܻ: ݽٕ = Gradle Module / @Module = Dagger Module
App ModularizationLink: https://developer.android.com/topic/modularization:app:android:feature:home:data:books:feature:reviews :feature:player:app:auto:core:network:data:reviewsਃ્ জ ӝמ ݆ইݶࢲ, ؊ ݽٕਸ ࣁ࠙ചೞҊ .
Gradle Build Setupplugins {id 'com.google.dagger.hilt.android'id 'kotlin-kapt'}dependencies {implementation 'com.google.dagger:hilt-android:2.48'kapt 'com.google.dagger:hilt-compiler:2.48'}ݽٕਸ ୶оೡ ٸ݃ ۄ࠳۞ܻ ࢸܳ ߈ࠂೠ.ח Convention Pluginsਵ۽ ѐࢶೡ ࣻ .“Gradle Kotlin ஶ߮࣌ ۞Ӓੋਵ۽ ബਯਵ۽ ݣ౭ ݽٕ ҙܻೞӝ” ߊܳ ଵҊ೧ ࠅ Ѫ.plugins {id 'example.android.hilt'}
App Modularization: @ModuleLink: https://developer.android.com/topic/modularization:app:android:feature:home:data:books:feature:reviews :feature:player:app:auto:core:network:data:reviews@Module@Module@Moduleп ݽٕ݃ @Moduleਸ ೡ ࣻ .
App Modularization: @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 { ... }@HiltAndroidAppclass MyApp : Application()٘۽ח ۠ ഋకо ؼ ࣻ .
hilt_metadataWithout Classpath Aggregation:app:android:feature:home:data:books:core:networkimplementationimplementationapi@Metadata@Metadata@InstallIn@InstallIn@InstallIn@Generated("dagger.hilt")interface MyApp_HiltComponents {@Component(modules = [FeatureHomeModule::class,DataBooksModule::class,...])interface SingletonC}Link: https://medium.com/androiddevelopers/mad-skills-series-hilt-under-the-hood-9d89ee227059ೞ݅ জ ݽٕীࢲ Ӕೡ ࣻ হח @Module জ ઓࢿ Ӓېী ನೣؼ ࣻ হ.CoreNetworkModule::class,
hilt_metadataWith Classpath Aggregation:app:android:feature:home:data:books:core:networkimplementationimplementationapi@Metadata@Metadata@Metadata@InstallIn@InstallIn@InstallIn@Generated("dagger.hilt")interface MyApp_HiltComponents {@Component(modules = [FeatureHomeModule::class,DataBooksModule::class,...])interface SingletonC}Link: https://medium.com/androiddevelopers/mad-skills-series-hilt-under-the-hood-9d89ee227059Classpath Aggregationਸ ਊೞৈ, ޙઁܳ ೧ѾೞҊ .CoreNetworkModule::class,
App ArchitectureUI LayerDomain LayerData LayerLink: https://developer.android.com/topic/architectureউ٘۽٘ ҕध ޙࢲীࢲ ӂೞח জ ইఃఫ
App Architecture:ui:domain:dataLink: https://developer.android.com/topic/architectureimplementationimplementation۠ ݽٕ ҳઑۄҊ о೧ࠁ.
App Architecture:dataclass ExampleUseCase @Inject constructor(private val repository: ExampleRepository) { ... }:ui:domainclass ExampleRepository @Inject constructor() { ... }Hiltܳ ਊೞৈ, ܲ ݽٕ ઓࢿਸ ੑೡ ࣻ .
App Architecture: interface, class ܻ࠙:domain:dataclass ExampleUseCase @Inject constructor(private val repository: ExampleRepository) { ... }class ExampleRepository @Inject constructor() { ... }ҳഅী ઓࢿਸ ыח Ѫ ࠁח,
App Architecture: interface, class ܻ࠙:domain:datainterface ExampleRepositoryclass ExampleRepositoryImpl @Inject constructor() : ExampleRepository { ... }@Module@InstallIn(SingletonComponent::class)interface DataModule {@Binds fun bindRepository(impl: ExampleRepositoryImpl) : ExampleRepository}class ExampleUseCase @Inject constructor(private val repository: ExampleRepository) { ... }interface৬ classܳ ܻ࠙ೞৈ, ҳഅܳ ଵઑೞ ঋب۾ ѐࢶೡ ࣻ .
App Architecture: internal:domain:dataLink: https://kotlinlang.org/docs/visibility-modifiers.html#modulesinterface ExampleRepositoryinternal 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) { ... }؊ աইо ݽٕ ৻ࠗীࢲח Ӕೡ ࣻ হب۾, internal ఃਕ٘ܳ ਊೡ ࣻ .
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 {@Bindsfun bindRepository(impl: ExampleRepositoryImpl) : ExampleRepository}internal @Module ݽٕ ৻ࠗীࢲ Ӕೡ ࣻ হਵ۽, HiltWrapperܳ ࢤࢿೞৈ
internal @Module न Componentী ୶о೧ળ. Ӓ۞ա…public final class ExampleApplication_HiltComponents {@Component(modules = {ApplicationContextModule.class,ActivityRetainedCBuilderModule.class,HiltWrapper_DataModule.class,})@Singletonpublic abstract static class SingletonC implementsHiltWrapper_ActivityRetainedComponentManager_ActivityRetainedComponentBuilderEntryPoint,SingletonComponent,GeneratedComponent {}}
App Architecture: internal ޙઁېझ݃ internal ఃਕ٘ܳ ୶о೧ঠ ೠ. (߈ࠂ স)=“ܲ ߑߨਸ Ҋ೧ࠁ…”=ѐߊо ֬ӝ औ. (पࣻ ਬߊ)
App Architecture: Clean Architecture ֤ۆ?UI LayerDomain LayerData LayerLink: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.htmlUI LayerDomain LayerData Layerinterface ExampleRepositoryinterface ExampleRepositoryvsinterfaceܳ بݫੋ ݽٕ۽ زೠݶ???
App Architecture: Clean Architecture ֤ۆ?:domain:datainterface ExampleRepositoryinternal 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) { ... }
App Architecture: Clean Architecture ֤ۆ?:domain:dataclass ExampleUseCase @Inject constructor(private val repository: ExampleRepository) { ... }interface ExampleRepositoryinternal class ExampleRepositoryImpl @Inject constructor() : ExampleRepository { ... }@Module@InstallIn(SingletonComponent::class)internal interface DataModule {@Binds fun bindRepository(impl: ExampleRepositoryImpl) : ExampleRepository}Ӓۡ٠೧ ࠁੋ. بݫੋ ݽٕ ೞաۄݶ…
App Architecture: Clean Architecture ֤ۆ?:domain-qux:domain-baz:domain-bar:domain-foointerface Bazclass BazImpl(bar: Bar) : Bazinterface Barclass BarImpl(foo: Foo) : Barinterface Fooclass FooImpl() : Foointerface Quxclass QuxImpl(baz: Baz) : Quxبݫੋ ݽٕ ৈۤݶ, interfaceܳ য٣ী ىঠ ೡө???
App Architecture: Clean Architecture ֤ۆ?:domain-qux:domain-baz:domain-bar:domain-fooclass BazImpl(bar: Bar) : Bazinterface Barclass BarImpl(foo: Foo) : Barinterface Fooclass FooImpl() : Foointerface Quxclass QuxImpl(baz: Baz) : Quxinterface Bazࢎਊೞח ݽٕ۽ ѹঠ ೞա???
App Architecture: Clean Architecture ֤ۆ?:domain-qux:domain-bar:domain-foointerface Barclass BarImpl(foo: Foo) : Barinterface Fooclass FooImpl() : Foointerface Quxclass QuxImpl(bar: Bar) : QuxӒۢ ৈ۞ ݽٕীࢲ ೞա interfaceܳ ࢎਊೞҊ ݶ???interface Bazclass BazImpl(bar: Bar) : Baz:domain-baz
App Architecture: Clean Architecture ֤ۆ?:domain-qux:domain-bar:domain-fooclass BarImpl(foo: Foo) : Barinterface Fooclass FooImpl() : Foointerface Quxclass QuxImpl(bar: Bar) : Quxinterface Barinterfaceܳ ӡ ਤо গݒೞ…:domain-bazinterface Bazclass BazImpl(bar: Bar) : Bazinterface Bar
App Architecture: ݽٕ ܻ࠙:domain-qux:domain-bar-apiinterface৬ classܳ пп ܲ ݽٕ۽ ܻ࠙ೞݶ ೧Ѿػ!:domain-baz:domain-bar-implinterface Barclass BarImpl(foo: Foo) : Barinterface Quxclass QuxImpl(bar: Bar) : Quxinterface Bazclass BazImpl(bar: Bar) : Baz
App Architecture: ݽٕ ܻ࠙:domain-qux:domain-bar-apiҳഅח @Moduleਸ ా೧ ੑೠ.:domain-baz:domain-bar-implinterface Barclass BarImpl(foo: Foo) : Bar ->interface Quxclass QuxImpl(bar: Bar) : Qux@Moduleinterface Bazclass BazImpl(bar: Bar) : Baz
App Architecture: ݽٕ ܻ࠙:domain-qux-impl:domain-baz-impl:domain-bar-impl:domain-foo-implclass BazImpl(bar: Bar) : Bazclass BarImpl(foo: Foo) : Barclass FooImpl() : Fooclass QuxImpl(baz: Baz) : Quxݽٕ ױਤী ઓࢿ ਗ(DIP)ਸ ਊೡ ࣻ .:domain-qux-api:domain-baz-api:domain-bar-api:domain-foo-apiinterface Bazinterface Barinterface Foointerface QuxLink: https://en.wikipedia.org/wiki/Dependency_inversion_principle
App Modularization: Final!:app:android:feature:home-api :data:books-api:data:books-impl:app:android:feature:home:data:books:feature:home-implBefore After୭ઙਵ۽ জ ݽٕ݅ ࣁࠗ ݽٕী Ӕೡ ࣻ ѱ ѐࢶೡ ࣻ .
App Modularization: Final! (+ runtimeOnly):app:android:feature:home-api :data:books-api:data:books-implruntimeOnly:app:android:feature:home:data:books:feature:home-implruntimeOnlyBefore AfterLink: https://developer.android.com/build/dependencies#runtimeOnlyজ ݽٕب Ӕೞ ޅೞѱ, ઓࢿ Ӓېী݅ ನೣغب۾ ೡ ࣻب .
Summary❏ Dagger Hilt ղࠗ٘ ࠙ࢳ• ઓࢿ Ӓېо ࢤࢿغҊ, ઓࢿਸ ੑೞח ߈ੋ җਸ ঌইࠌ.• @Provides ࠁח @Inject, @Bindsਸ ࢎਊೞ.• Scopeܳ ࢶೞח ਤܳ ೞ.• Lazyࠁח Scope + Providerਸ ࢎਊೞ.❏ ݣ౭ݽٕীࢲ ઓࢿ ੑ• Convention Pluginsਸ ࢎਊೞ.• internal ࠁח, ݽٕਸ ܻ࠙ೞৈ Ӕਸ ઁೠೞ. (api, impl)Sample: https://github.com/fornewid/dagger-hilt-example/
хࢎפ!Slide Link: https://speakerdeck.com/fornewid