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

Dagger Hilt로 의존성 주입하기

Dagger Hilt로 의존성 주입하기

2023년 7월 29일 (토) I/O Extended 2023 Seoul 행사에서의 발표자료입니다.
https://festa.io/events/3683

Sungyong An

July 29, 2023
Tweet

More Decks by Sungyong An

Other Decks in Programming

Transcript

  1. Intro “৵ ૑Ә Dagger Hiltܳ…?” “Dagger Hiltী ࢜۽਍ ߸҃ࢎ೦੉ ੓աਃ?”

    “׮ܲ ੄ઓࢿ ઱ੑ ۄ੉࠳۞ܻ৬ ࠺Үೞח ղਊੋоਃ?” 🤔
  2. Intro “৵ ૑Ә Dagger Hiltܳ…?” “Dagger Hiltী ࢜۽਍ ߸҃ࢎ೦੉ ੓աਃ?”

    “׮ܲ ੄ઓࢿ ઱ੑ ۄ੉࠳۞ܻ৬ ࠺Үೞח ղਊੋоਃ?” 🤔
  3. Intro ੄ઓࢿ ઱ੑ(DI)਷ ೞա੄ ё୓о ׮ܲ ё୓੄ ੄ઓࢿਸ ઁҕೞח ӝߨ੉׮.

    ੄ઓࢿ ઱ੑ੄ ੄بח ё୓੄ ࢤࢿҗ ࢎਊ੄ ҙबਸ ܻ࠙ೞח Ѫ੉׮. Dependency Injection? Link: https://en.wikipedia.org/wiki/Dependency_injection
  4. // Without Dependency Injection class Car { private val engine:

    Engine = Engine() fun start() { engine.start() } } fun main(args: Array) { val car = Car() car.start() } ੄ઓࢿ ઱ੑ হ੉, Car ௿ېझ ղࠗীࢲ Engineਸ ࢤࢿೞח ௏٘ੑפ׮.
  5. // Dependency Injection (Constructor Injection) class Car( private val engine:

    Engine ) { fun start() { engine.start() } } fun main(args: Array) { val engine = Engine() val car = Car(engine) car.start() } ੄ઓࢿ ઱ੑীࢲח Car ௿ېझ ࢤࢿ੗ী Engineਸ ੹׳ೞѢա,
  6. // Dependency Injection (Field Injection) class Car { lateinit var

    engine: Engine fun start() { engine.start() } } fun main(args: Array) { val car = Car() car.engine = Engine() car.start() } ৻ࠗীࢲ Engineਸ ࢤࢿೞৈ ೙٘ ઱ੑਵ۽ ੹׳೤פ׮.
  7. Intro DI੄ ਗ஗ਸ ٮܰݶ ഴܯೠ জ ইఃఫ୊ܳ ਤೠ ష؀ܳ ݃۲ೡ

    ࣻ ੓׮. • ௏٘ ੤ࢎਊ оמ • ܻಂష݂ ಞ੄ࢿ • పझ౟ ಞ੄ࢿ Dependency Injection ੉੼? Link: https://en.wikipedia.org/wiki/Dependency_injection
  8. Intro 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 ࢶఖೠ ੉ਬ? ૑ࣘоמࢿ …
  9. Intro • ё୓ܳ ࢤࢿೞח Ҕҗ ࢎਊೞח Ҕ੉ ܻ࠙غয, ௏٘ܳ ୶੸ೞӝ

    য۵ѱ ݅ٚ׮. • ✅ Android Studioח Dagger ߂ Hilt ҙ۲ ௏٘ р੄ ఐ࢝ਸ ૑ਗೠ׮. https://medium.com/androiddevelopers/dagger-navigation-support-in-android-studio-49aa5d149ec9 • ௏٘о ࠗ࠙ࠗ࠙ ܻ࠙غয, दझమ ੹୓о ࣻ೯ೞח ੘সਸ ౵ঈೞӝ য۵׮. • ࢎਊೞח ౠ੿ DI ೐ۨ੐ਕ௼ী ੄ઓೞѱ ػ׮. Dependency Injection == ? Link: https://en.wikipedia.org/wiki/Dependency_injection 💯
  10. Intro Java, Kotlin MVC, MVP, MVVM, MVI Language Architecture Java

    Threads, AsyncTask, HandlerThread, Guava, RxJava, Kotlin Coroutines Asynchronous work View, Layout XML, anko, Litho, Compose, ButterKnife, Kotlin Android Extensions, DataBinding, ViewBinding Android Universal Image Loader, Picasso, Glide, Coil, Volley, OkHttp, Retrofit, Ktor, Jackson, Gson, Moshi, kotlinx.serialization User Interface Network Background work Service, AlarmManager, JobScheduler, GCMNetworkManager, android-job, JobDispatcher, JobService, WorkManager
  11. Intro Java, Kotlin MVC, MVP, MVVM, MVI Language Architecture Java

    Threads, AsyncTask, HandlerThread, Guava, RxJava, Kotlin Coroutines Asynchronous work View, Layout XML, anko, Litho, Compose, ButterKnife, Kotlin Android Extensions, DataBinding, ViewBinding Android Universal Image Loader, Picasso, Glide, Coil, Volley, OkHttp, Retrofit, Ktor, Jackson, Gson, Moshi, kotlinx.serialization User Interface Network Background work Service, AlarmManager, JobScheduler, GCMNetworkManager, android-job, JobDispatcher, JobService, WorkManager Nothing Lasts Forever
  12. “Hiltܳ ੉ਊೞৈ Android জী ੄ઓࢿ ઱ੑ ಁఢਸ ҳഅೞغ, ݾ੸ਸ ஂೡ

    ݅ఀ݅ ੸׼൤ ࢎਊೞח ߑߨਸ Ҋ޹೧ ࠁ੗.” ݾ಴
  13. Hiltо ઁҕೞח জী ੄ઓࢿ ઱ੑೞח ߑߨਸ ঌইࠄ׮. Jetpack ۄ੉࠳۞ܻ৬ োزغח

    ࠗ࠙ب рױ൤ ࢓ಝࠄ׮. ݾ੸ী ݏѱ, জীࢲ Hiltܳ ࢎਊೞח ഋకܳ Ҋ޹೧ ࠄ׮. ӝࠄ о੉٘ࠁ׮ ؊ ࠂ੟ೞѱ ࢎਊೞח Ѫ੉ ա਷ ࠗ࠙җ য়൤۰ ࢎਊೞ૑ ঋח Ѫ੉ ա਷ ࠗ࠙ ١ਸ ࢤп೧ ࠄ׮. Dagger Hilt Thinking Usages ݾର
  14. // build.gradle buildscript { repositories { mavenCentral() } dependencies {

    classpath 'com.google.dagger:hilt-android-gradle-plugin:2.47' } } // app/build.gradle apply plugin: 'com.google.dagger.hilt.android' apply plugin: 'kotlin-kapt' dependencies { implementation 'com.google.dagger:hilt-android:2.47' kapt 'com.google.dagger:hilt-compiler:2.47' } Link: https://dagger.dev/hilt/gradle-setup Gradle Setup
  15. Section #1 ӝࠄ੸ੋ Dagger Hilt ࢎਊߑߨਸ ࢓ಝࠁ੗. • @HiltAndroidApp, @AndroidEntryPoint,

    @EntryPoint • Components • SingletonComponent, ViewModelComponent, ActivityComponent, ... • Scopes • @Singleton, @ViewModelScoped, @ActivityScoped, … • Modules • @Inject, @Module, @Provides, @Binds, @Qualifier, @Lazy, … Hilt Basics Link: https://dagger.dev/hilt/quick-start
  16. @HiltAndroidApp class ExampleApplication : Application() { @Inject lateinit var bar:

    Bar override fun onCreate() { super.onCreate() // Use bar } } (1) Hiltܳ ࢎਊೞח ݽٚ জ਷ Applicationী HiltAndroidAppਸ ୶о೧ঠ ೤פ׮.
  17. class ExampleApplication : Hilt_ExampleApplication() public abstract class Hilt_ExampleApplication extends Application

    implements ... { @CallSuper @Override public void onCreate() { hiltInternalInject(); super.onCreate(); } ... } Generated Gradle ೒۞Ӓੋਸ ੉ਊೞݶ ࢚ࣘਸ ా೧
  18. public final class ExampleApplication_MembersInjector implements MembersInjector<ExampleApplication> { private final Provider<Bar>

    barProvider; public ExampleApplication_MembersInjector(Provider<Bar> barProvider) { this.barProvider = barProvider; } @Override public void injectMembers(ExampleApplication instance) { injectBar(instance, barProvider.get()); } public static void injectBar(ExampleApplication instance, Bar bar) { instance.bar = bar; } } Generated ੄ઓࢿب ઱ੑೡ ࣻ ੓णפ׮.
  19. @AndroidEntryPoint class ExampleActivity : Activity() { @Inject lateinit var bar:

    Bar override fun onCreate() { super.onCreate() // Use bar } } (2) Activityח AndroidEntryPointܳ ੉ਊೞৈ, Field Injection੉ оמ೤פ׮.
  20. class ExampleActivity : Hilt_ExampleActivity() public abstract class Hilt_ExampleActivity extends Activity

    implements ... { Hilt_ExampleActivity() { super(); _initHiltInternal(); } private void _initHiltInternal() { addOnContextAvailableListener(new OnContextAvailableListener() { @Override public void onContextAvailable(Context context) { inject(); } }); } } Generated ݃ଲо૑۽ ࢚ࣘਸ ా೧, ੄ઓࢿਸ ઱ੑ೤פ׮.
  21. @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() { ... } Fragment, View, Service, BroadcastReceiverب زੌ೤פ׮.
  22. public abstract class Hilt_ExampleFragment extends Fragment class ExampleFragment : Hilt_ExampleFragment()

    { ... } public abstract class Hilt_ExampleView extends View class ExampleView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, ) : Hilt_ExampleView(context, attrs, defStyleAttr) { ... } public abstract class Hilt_ExampleService extends Service class ExampleService : Hilt_ExampleService() { ... } public abstract class Hilt_ExampleBroadcastReceiver extends BroadcastReceiver class ExampleBroadcastReceiver : Hilt_ExampleBroadcastReceiver() { ... } Generated ݃ଲо૑۽ ࢚ࣘਸ ా೧, ੄ઓࢿਸ ઱ੑ೤פ׮.
  23. class ExampleContentProvider : ContentProvider() { @EntryPoint @InstallIn(SingletonComponent::class) interface ExampleContentProviderEntryPoint {

    fun bar(): Bar } override fun query(...): Cursor { val appContext = context?.applicationContext ?: throw IllegalStateException() val hiltEntryPoint = EntryPointAccessors.fromApplication( appContext, ExampleContentProviderEntryPoint::class.java ) val bar = hiltEntryPoint.bar() ... } } (3) ContentProviderח EntryPointܳ ੉ਊೞৈ, ੄ઓࢿਸ ઱ੑೡ ࣻ ੓णפ׮.
  24. @Module @InstallIn(SingletonComponent::class) object ExampleModule { @Provides fun providesBar(foo: Foo): Bar

    = Bar(foo) @Provides fun providesFoo(): Foo = Foo() } (4) ઱ੑ೧ঠ ೡ ੄ઓࢿਸ Moduleী ੿੄ೡ ࣻ ੓णפ׮.
  25. @Module @InstallIn(SingletonComponent::class) object ExampleModule { @Provides fun providesBar(foo: Foo): Bar

    = Bar(foo) @Provides fun providesFoo(): Foo = Foo() } (5) InstallInਸ ੉ਊೞৈ, Moduleਸ ࢸ஖ೞ۰ח Componentܳ ੿੄೤פ׮.
  26. Section #1 ׮নೠ উ٘۽੉٘ ҳࢿਃࣗ੄ ࣻݺ ઱ӝী ੗زਵ۽ ా೤غח ӝࠄ

    ઁҕ Componentо ੓णפ׮. п ҳࢿ ਃࣗ੄ ࣻݺী ؀ೠ ߄ੋ٬ ߧਤܳ ૑੿ೞחؘ ࢎਊغח Scope Annotation੉ ੓णפ׮. Component Link: https://dagger.dev/hilt/components
  27. @Module @InstallIn(SingletonComponent::class) object ExampleModule { @Provides fun providesBar(foo: Foo): Bar

    = Bar(foo) @Provides fun providesFoo(): Foo = Foo() } Foo Bar (6) Providesܳ ੉ਊೞৈ, ੄ઓࢿਸ ઁҕೡ ࣻ ੓णפ׮.
  28. public final class ExampleModule_ProvidesFooFactory implements Factory<Foo> { @Override public Foo

    get() { return providesFoo(); } public static ExampleModule_ProvidesFooFactory create() { return InstanceHolder.INSTANCE; } public static Foo providesFoo() { return Preconditions.checkNotNullFromProvides(ExampleModule.INSTANCE.providesFoo()); } private static final class InstanceHolder { private static final ExampleModule_ProvidesFooFactory INSTANCE = new ExampleModule_ProvidesFooFactory(); } } Generated пп੄ @Provides ೣࣻ݃׮ Factory ௿ېझо ੗ز ࢤࢿؾפ׮.
  29. public final class ExampleModule_ProvidesBarFactory implements Factory<Bar> { private final Provider<Foo>

    fooProvider; public ExampleModule_ProvidesBarFactory(Provider<Foo> fooProvider) { this.fooProvider = fooProvider; } @Override public Bar get() { return providesBar(fooProvider.get()); } public static ExampleModule_ProvidesBarFactory create(Provider<Foo> fooProvider) { return new ExampleModule_ProvidesBarFactory(fooProvider); } public static Bar providesBar(Foo foo) { return Preconditions.checkNotNullFromProvides(ExampleModule.INSTANCE.providesBar(foo)); } } Generated
  30. @Module @InstallIn(SingletonComponent::class) object ExampleModule { @Provides fun providesBar(foo: Foo): Bar

    = BarImpl(foo) @Provides fun providesFoo(): Foo = FooImpl() } Foo Bar FooImpl BarImpl (7) ੋఠಕ੉झ৬ ҳഅ୓ܳ ܻ࠙ೡ ࣻب ੓णפ׮.
  31. @Module @InstallIn(SingletonComponent::class) object ExampleModule { // unscoped @Provides fun providesBar(foo:

    Foo): Bar = BarImpl(foo) @Singleton @Provides fun providesFoo(): Foo = FooImpl() } (8) Scopeܳ ૑੿ೞݶ, ೧׼ Component੄ ࣻݺ੉ ՘զ ٸө૑ ਬ૑ؾפ׮.
  32. private static final class SingletonCImpl extends ... { private Provider<Foo>

    providesFooProvider; private SingletonCImpl() { this.providesFooProvider = DoubleCheck.provider( () -> ExampleModule_ProvidesFooFactory.providesFoo() ); } public Bar providesBar() { return ExampleModule_ProvidesBarFactory .providesBar((Foo)this.providesFooProvider.get()) .bar(); } } Generated Scopeо ૑੿غ૑ ঋਵݶ, ݒߣ ࢤࢿ೤פ׮.
  33. @Module @InstallIn(SingletonComponent::class) interface ExampleModule { @Binds fun bindsBar(impl: BarImpl): Bar

    @Singleton @Binds fun bindsFoo(impl: FooImpl): Foo } Foo Bar FooImpl BarImpl (9) Inject৬ Bindsܳ ੉ਊೞৈ, ҳഅ୓ܳ ੋఠಕ੉झ ഋక۽ ઁҕೡ ࣻب ੓णפ׮. class BarImpl @Inject constructor(private val foo: Foo) : Bar { ... } class FooImpl @Inject constructor() : Foo { ... }
  34. private static final class SingletonCImpl extends ... { private Provider<FooImpl>

    fooImplProvider; private Provider<Foo> bindsFooProvider; private SingletonCImpl() { this.fooImplProvider = () -> new FooImpl(); this.bindsFooProvider = DoubleCheck.provider(this.fooImplProvider); } public Bar providesBar() { return new BarImpl((Foo) this.bindsFooProvider.get()); } } Generated Provides৬ ׮ܰѱ, Bindsח Factory ௿ېझо ࢤࢿغ૑ ঋणפ׮.
  35. Section #1 Dagger Hilt۽ ViewModelী ੄ઓࢿਸ ઱ੑೡ ࣻ ੓णפ׮. Dagger

    Hilt۽ Workerী ੄ઓࢿਸ ઱ੑೡ ࣻ ੓णפ׮. ViewModel WorkManager With Jetpack Libraries
  36. @HiltViewModel class ExampleViewModel @Inject constructor( private val savedStateHandle: SavedStateHandle, private

    val repository: ExampleRepository ) : ViewModel() { ... } @AndroidEntryPoint class ExampleActivity : Activity() { private val exampleViewModel: ExampleViewModel by viewModels() ... } ViewModel Activityীࢲ ੄ઓࢿ ઱ੑػ ViewModelী ੽Ӕೞח ௏٘ੑפ׮. ViewModel਷ AndroidEntryPoint ؀न, HiltViewModelܳ ࢎਊೞৈ ੄ઓࢿਸ ઱ੑ೤פ׮.
  37. public abstract class Hilt_ExampleActivity extends Activity implements ... { ...

    @Override public ViewModelProvider.Factory getDefaultViewModelProviderFactory() { return DefaultViewModelFactories .getActivityFactory(this, super.getDefaultViewModelProviderFactory()); } } Generated Activity੄ Factoryܳ Hilt੄ ҳഅ଻۽ overrideೞח ߑधੑפ׮.
  38. public final class DefaultViewModelFactories { public static ViewModelProvider.Factory getActivityFactory( ComponentActivity

    activity, ViewModelProvider.Factory delegateFactory) { return EntryPoints.get(activity, ActivityEntryPoint.class) .getHiltInternalFactoryFactory() .fromActivity(activity, delegateFactory); } @EntryPoint @InstallIn(ActivityComponent.class) public interface ActivityEntryPoint { InternalFactoryFactory getHiltInternalFactoryFactory(); } ... Library Internal ղࠗ੸ਵ۽ EntryPointܳ ࢎਊ೤פ׮.
  39. @HiltViewModel class ExampleViewModel @Inject constructor( private val savedStateHandle: SavedStateHandle, private

    val repository: ExampleRepository ) : ViewModel() { ... } import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( viewModel: MyViewModel = viewModel() ) { ... } Composeীࢲ ੄ઓࢿ ઱ੑػ ViewModelী ੽Ӕೞח ௏٘ੑפ׮.
  40. package androidx.lifecycle.viewmodel.compose @Composable public inline fun <reified VM : ViewModel>

    viewModel( viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) { "No ViewModelStoreOwner was provided via LocalViewModelStoreOwner" }, key: String? = null, factory: ViewModelProvider.Factory? = null, extras: CreationExtras = if (viewModelStoreOwner is HasDefaultViewModelProviderFactory) { viewModelStoreOwner.defaultViewModelCreationExtras } else { CreationExtras.Empty } ): VM = viewModelStoreOwner.get(VM::class.java, key, factory, extras) Library Internal CompositionLocalਸ ੉ਊೞח ߑधੑפ׮.
  41. package androidx.lifecycle.viewmodel.compose public object LocalViewModelStoreOwner { private val LocalViewModelStoreOwner =

    compositionLocalOf<ViewModelStoreOwner?> { null } public val current: ViewModelStoreOwner? @Composable get() = LocalViewModelStoreOwner.current ?: LocalView.current.findViewTreeViewModelStoreOwner() } Library Internal LocalViewܳ ా೧, ViewModelStoreOwnerী ੽Ӕ೤פ׮.
  42. package androidx.activity; public class ComponentActivity extends androidx.core.app.ComponentActivity implements ViewModelStoreOwner {

    private void initViewTreeOwners() { ... ViewTreeViewModelStoreOwner.set(getWindow().getDecorView(), this); ... } } Library Internal ѾҴ ViewModelStoreOwnerܳ ੉ਊೞৈ,
  43. private fun <VM : ViewModel> ViewModelStoreOwner.get( javaClass: Class<VM>, key: String?

    = null, factory: ViewModelProvider.Factory? = null, extras: CreationExtras = ... ): VM { val provider = if (factory != null) { ViewModelProvider(this.viewModelStore, factory, extras) } else if (this is HasDefaultViewModelProviderFactory) { ViewModelProvider(this.viewModelStore, this.defaultViewModelProviderFactory, extras) } else { ViewModelProvider(this) } return if (key != null) { provider[key, javaClass] } else { provider[javaClass] } } Library Internal Activity੄ Factoryী ੽Ӕ೤פ׮.
  44. // app/build.gradle apply plugin: 'kotlin-kapt' dependencies { implementation 'androidx.hilt:hilt-work:1.0.0' kapt

    'androidx.hilt:hilt-compiler:1.0.0' } WorkManager (1) WorkManagerח ۄ੉࠳۞ܻܳ ୶о ࢸ஖೧ঠ ೤פ׮.
  45. @HiltWorker class ExampleWorker @AssistedInject constructor( @Assisted appContext: Context, @Assisted workerParams:

    WorkerParameters, bar: Bar, ) : CoroutineWorker(appContext, workerParams) { override suspend fun doWork(): Result { ... return Result.success() } } (2) Workerח AndroidEntryPoint ؀न, HiltWorkerܳ ࢎਊ೤פ׮. ӒܻҊ Inject ؀न, AssistedInject / Assistedܳ ੉ਊೞৈ ࢤࢿ੗ী ӝࠄ ݒѐ߸ࣻܳ ઱ੑ೤פ׮.
  46. public final class ExampleWorker_Factory { private final Provider<ExampleUseCase> exampleProvider; public

    ExampleWorker_Factory(Provider<ExampleUseCase> exampleProvider) { this.exampleProvider = exampleProvider; } public ExampleWorker get(Context context, WorkerParameters params) { return newInstance(context, params, exampleProvider.get()); } ... public static ExampleWorker newInstance(Context context, WorkerParameters params, ExampleUseCase example) { return new ExampleWorker(context, params, example); } } Generated ੄ઓࢿਸ ୶оೞח Factory৬
  47. public interface ExampleWorker_AssistedFactory extends WorkerAssistedFactory<ExampleWorker> {} public final class ExampleWorker_AssistedFactory_Impl

    implements ExampleWorker_AssistedFactory { private final ExampleWorker_Factory delegateFactory; ExampleWorker_AssistedFactory_Impl(ExampleWorker_Factory delegateFactory) { this.delegateFactory = delegateFactory; } @Override public ExampleWorker create(Context context, WorkerParameters parameters) { return delegateFactory.get(context, parameters); } public static Provider<ExampleWorker_AssistedFactory> create( ExampleWorker_Factory delegateFactory) { return InstanceFactory.create(new ExampleWorker_AssistedFactory_Impl(delegateFactory)); } } Generated ӝࠄ ݒѐ߸ࣻܳ ୶оೞח Factory. 2о૑о ࢤࢿؾפ׮.
  48. public interface WorkerAssistedFactory<T extends ListenableWorker> { @NonNull T create(@NonNull Context

    context, @NonNull WorkerParameters parameters); } @Module @InstallIn(SingletonComponent.class) public interface ExampleWorker_HiltModule { @Binds @IntoMap @StringKey("com.example.dagger.hilt.ExampleWorker") WorkerAssistedFactory<? extends ListenableWorker> bind(ExampleWorker_AssistedFactory factory); } Generated Bindsܳ ੉ਊೞৈ, Workerо Mapਵ۽ ޘੑפ׮.
  49. @Module @InstallIn(SingletonComponent.class) abstract class WorkerFactoryModule { @NonNull @Multibinds abstract Map<String,

    WorkerAssistedFactory<? extends ListenableWorker>> workerFactoriesMap(); @NonNull @Provides static HiltWorkerFactory provideFactory(@NonNull Map<String, Provider<WorkerAssistedFactory<? extends ListenableWorker>>> workerFactories) { return new HiltWorkerFactory(workerFactories); } } Generated ݽٚ Worker੄ Providerח HiltWorkerFactoryী ੹׳ؾפ׮.
  50. public final class HiltWorkerFactory extends androidx.work.WorkerFactory { private final Map<String,

    Provider<WorkerAssistedFactory<? extends ListenableWorker>>> mWorkerFactories; ... @Nullable @Override public ListenableWorker createWorker(@NonNull Context appContext, @NonNull String workerClassName, @NonNull WorkerParameters workerParameters) { Provider<WorkerAssistedFactory<? extends ListenableWorker>> factoryProvider = mWorkerFactories.get(workerClassName); if (factoryProvider == null) { return null; } return factoryProvider.get().create(appContext, workerParameters); } } Library Internal п Providerח Workerܳ पઁ۽ ࢤࢿ೧ঠ ೡ ٸ ࢎਊؾפ׮.
  51. @HiltAndroidApp class ExampleApplication : Application(), Configuration.Provider { @Inject lateinit var

    workerFactory: HiltWorkerFactory override fun getWorkManagerConfiguration() = Configuration.Builder() .setWorkerFactory(workerFactory) .build() } val exampleWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<ExampleWorker>().build() WorkManager.getInstance(context).enqueue(exampleWorkRequest) (3) HiltWorkerFactoryܳ Applicationী ઱ੑ ߉ই, WorkManagerܳ ୡӝചೞݶ ࢸ੿੉ ৮ܐؾפ׮.
  52. Section #2 WorkManagerח ؀ࠗ࠙੄ ߔӒۄ਍٘ ੘সী ӂ੢ೞח ӝࠄ API۽, ౠ൤

    Android 14 ࠗఠח FGSܳ ؀नೞח ߑߨਵ۽ب ӂ੢ೞҊ ੓׮. ੼੼ ؊ ݆੉ ࢎਊೞҊ ੓ח, WorkManagerী ੄ઓࢿ ઱ੑೡ ٸ Ҋ޹ೡ݅ೠ ࠗ࠙ਸ ࢓ಝࠁ੗. Coroutinesח উ٘۽੉٘ জীࢲ ࠺زӝ ୊ܻী ݆੉ ࢎਊغח ߑߨ੉׮. ࢎਊೞח ਤ஖ী ٮۄ যڃ CoroutineScopeܳ ࢎਊೞח Ѫ੉ ੸੺ೠ૑ Ҋ޹೧ࠁ੗. WorkManager Coroutines উ٘۽੉٘ জ਷ ӝࠄ ஹನք౟ ৻ীب ׮নೠ ۄ੉࠳۞ܻܳ ੉ਊೞৈ ѐߊೠ׮. ੉۠ ۄ੉࠳۞ܻܳ ࢎਊೡ ٸ ੄ઓࢿਸ ઱ੑೞח ߑߨਵ۽ EntryPoint ࢎਊਸ Ҋ޹೧ࠁ੗. EntryPoint Thinking Usages
  53. Section #2 о੉٘ ޙࢲীࢲח ࢸݺೞ૑ ঋח ࠗ࠙ਸ Ҋ޹೧ࠁ੗. • WorkManagerܳ

    ࢎਊೞ۰ݶ ೦࢚ Contextо ೙ਃೞ׮. • ࢎਊೡ ࣻ ੓ח ਤ஖о ઁೠغח ޙઁܳ DI۽ ೧Ѿೡ ࣻ ੓׮. • WorkManagerח যڃ ࠗ࠙ਸ పझ౟ೞח Ѫ੉ જਸө? • Worker੄ ز੘ਸ పझ౟ೠ׮. (X) • Worker۽ प೯ೞ۰ח ۽૒ਸ పझ౟ೠ׮. (O) • WorkManager ੄ઓࢿਸ ऀѹࢲ, ਗೞח ࠗ࠙݅ਸ పझ౟ೡ ࣻ ੓׮. Thinking about WorkManager Link: https://developer.android.com/training/dependency-injection/hilt-jetpack#workmanager
  54. // Problem 1: val context: Context = ... // Where

    this from? val request = OneTimeWorkRequestBuilder<ExampleWorker>() .addTag(ExampleWorker.TAG) .build() WorkManager.getInstance(context).enqueue(request) WorkManagerܳ ࢎਊೞ۰ݶ Contextо ೙ਃೞ׮. WorkManager Context
  55. @Module @InstallIn(SingletonComponent::class) object TasksModule { @Singleton @Provides fun provideWorkManager( @ApplicationContext

    context: Context, ): WorkManager { return WorkManager.getInstance(context) } } DIܳ ੉ਊೞৈ, Context ੄ઓࢿਸ ऀӡ ࣻ ੓Ҋ WorkManager
  56. @AndroidEntryPoint class ExampleActivity : Activity() { @Inject lateinit var workManager:

    WorkManager } @HiltViewModel class ExampleViewModel @Inject constructor( private val workManager: WorkManager ) : ViewModel() ࢎਊೞ۰ח Ҕী WorkManager۽ ઱ੑ߉ਸ ࣻ ੓णפ׮. Example ViewModel WorkManager Example Activity
  57. // Problem 2: @AndroidEntryPoint class ExampleActivity : Activity() { @Inject

    lateinit var workManager: WorkManager } @HiltViewModel class ExampleViewModel @Inject constructor( private val workManager: WorkManager ) : ViewModel() val request = OneTimeWorkRequestBuilder<ExampleWorker>() .addTag(ExampleWorker.TAG) .build() workManager.enqueue(request) ೞ૑݅ Worker, WorkManager ١ ೒ۖಬ ௿ېझী ੄ઓࢿਸ ыѱ ؾפ׮. WorkManager Example Activity Example Worker
  58. @Module @InstallIn(SingletonComponent::class) interface TasksBindsModule { @Binds fun bindsExampleTasks(impl: ExampleTasksImpl): ExampleTasks

    } interface ExampleTasks { fun execute() } class ExampleTasksImpl @Inject constructor( private val workManager: WorkManager, ) : ExampleTasks { override fun execute() { val request = OneTimeWorkRequestBuilder<ExampleWorker>() .addTag(ExampleWorker.TAG) .build() workManager.enqueue(request) } } DIܳ ੉ਊೞৈ, ز੘਷ زੌೞ૑݅ WorkManager Example Worker Example Tasks
  59. @AndroidEntryPoint class ExampleActivity : Activity() { @Inject lateinit var exampleTasks:

    ExampleTasks } @HiltViewModel class ExampleViewModel @Inject constructor( private val exampleTasks: ExampleTasks ) : ViewModel() exampleTasks.execute() ೒ۖಬ ௿ېझী ؀ೠ ੄ઓࢿਸ ऀӡ ࣻ ੓णפ׮. ExampleTasks Example ViewModel Example Activity
  60. // Problem 3: @HiltWorker class ExampleWorker @AssistedInject constructor( @Assisted context:

    Context, @Assisted params: WorkerParameters, private val primary: PrimaryDependency, private val secondary: SecondaryDependency, private val tertiary: TertiaryDependency, ) : CoroutineWorker(context, params) { override suspend fun doWork(): Result { val success = /* Complex codes to test */ return if (success) { Result.success() } else { Result.failure() } } } Worker੄ ز੘җ ࠺ૉפझ ۽૒੉ ೠؘ ࢴৈ ੓णפ׮.
  61. @HiltWorker class ExampleWorker @AssistedInject constructor( @Assisted context: Context, @Assisted params:

    WorkerParameters, private val example: ExampleUseCase, ) : CoroutineWorker(context, params) { override suspend fun doWork(): Result { val success = example() return if (success) { Result.success() } else { Result.failure() } } } DIܳ ੉ਊೞৈ, ࠺ૉפझ ۽૒݅ ܻ࠙ೞৈ
  62. interface ExampleUseCase { operator suspend fun invoke(): Boolean } class

    ExampleUseCaseImpl @Inject constructor( private val primary: PrimaryDependency, private val secondary: SecondaryDependency, private val tertiary: TertiaryDependency, ) : ExampleUseCase { override operator suspend fun invoke(): Boolean { return /* Complex codes to test */ } } @Module @InstallIn(SingletonComponent::class) interface TasksBindsModule { @Binds fun bindsExampleUseCase(impl: ExampleUseCaseImpl): ExampleUseCase } Worker੄ ৉ೡਸ ୭ࣗചೡ ࣻ ੓णפ׮.
  63. Section #2 పझ౟ܳ Ҋ۰ೞৈ, CoroutineDispatcherܳ ૒੽ ੑ۱ೞ૑ ঋҊ ੄ઓࢿ ઱ੑೞৈ

    ࢎਊೞח ߑߨਸ ࢓ಝࠄ׮. Qualifierܳ ੉ਊೞৈ, ׮নೠ CoroutineDispatcherܳ ҳ ࠙ೞৈ ઱ੑೡ ࣻ ੓׮. জীࢲ ࢎਊೞӝ ੸׼ೠ CoroutineScopeܳ ࢓ಝࠁ੗. ౠ൤, Application ژח Service ߧਤ ղীࢲ ௏ܖ౯ਸ ҙܻ ೞח ߑߨਸ ঌইࠁҊ, Hilt۽ ੄ઓࢿ ઱ੑೞח Ѫ੉ о੢ જ਷ ߑߨੋ૑ Ҋ޹೧ ࠁ੗. CoroutineDispatcher CoroutineScope Thinking about Coroutines
  64. class Example { suspend fun doSomething(): Boolean { return withContext(Dispatchers.Default)

    { /* do something! */ } } } @Test fun test() { val example = Example() assertTrue(example.doSomething()) } ௏ܖ౯੉ ನೣغݶ যڌѱ పझ౟ೞաਃ? Link: https://developer.android.com/kotlin/coroutines/coroutines-best-practices#inject-dispatchers
  65. class Example( private val defaultDispatcher: CoroutineDispatcher = Dispatchers.Default, ) {

    suspend fun doSomething(): Boolean { return withContext(defaultDispatcher) { /* do something! */ } } } @Test fun test() { val testDispatcher: TestDispatcher = UnconfinedTestDispatcher() val example = Example(testDispatcher) assertTrue(example.doSomething()) } DIܳ ੉ਊೞৈ, TestDispatcherܳ ઱ੑೡ ࣻ ੓णפ׮. Link: https://developer.android.com/kotlin/coroutines/coroutines-best-practices#inject-dispatchers
  66. class Example @Inject constructor( private val defaultDispatcher: CoroutineDispatcher, ) {

    suspend fun doSomething(): Boolean { return withContext(defaultDispatcher) { /* do something! */ } } } @Module @InstallIn(SingletonComponent::class) object DispatchersModule { @Provides fun providesDefaultDispatcher(): CoroutineDispatcher = Dispatchers.Default } Hiltܳ ੉ਊೠ ௏٘ੑפ׮.
  67. class Example @Inject constructor( private val defaultDispatcher: CoroutineDispatcher, ) {

    suspend fun doSomething(): Boolean { return withContext(defaultDispatcher) { /* do something! */ } } } @Module @InstallIn(SingletonComponent::class) object DispatchersModule { @Provides fun providesDefaultDispatcher(): CoroutineDispatcher = Dispatchers.Default @Provides fun providesIoDispatcher(): CoroutineDispatcher = Dispatchers.IO // ??? } Ӓؘ۠ ׮ܲ ਬഋ੉ ೙ਃೞ׮ݶ যڌѱ ೧ঠ ೡөਃ?
  68. @Qualifier @Retention(AnnotationRetention.BINARY) annotation class DefaultDispatcher @Qualifier @Retention(AnnotationRetention.BINARY) annotation class IoDispatcher

    @Module @InstallIn(SingletonComponent::class) object DispatchersModule { @DefaultDispatcher @Provides fun providesDefaultDispatcher(): CoroutineDispatcher = Dispatchers.Default @IoDispatcher @Provides fun providesIoDispatcher(): CoroutineDispatcher = Dispatchers.IO } Qualifierܳ ੉ਊೞݶ ؾפ׮. Link: https://medium.com/androiddevelopers/create-an-application-coroutinescope-using-hilt-dd444e721528
  69. class Example @Inject constructor( @DefaultDispatcher private val defaultDispatcher: CoroutineDispatcher, )

    { suspend fun doSomething(): Boolean { return withContext(defaultDispatcher) { /* do something! */ } } } @Module @InstallIn(SingletonComponent::class) object DispatchersModule { @DefaultDispatcher @Provides fun providesDefaultDispatcher(): CoroutineDispatcher = Dispatchers.Default @IoDispatcher @Provides fun providesIoDispatcher(): CoroutineDispatcher = Dispatchers.IO } Default Dispatcherܳ ઱ੑೞח ௏٘ੑפ׮.
  70. class Example @Inject constructor( @IoDispatcher private val ioDispatcher: CoroutineDispatcher, )

    { suspend fun doSomething(): Boolean { return withContext(defaultDispatcher) { /* do something! */ } } } @Module @InstallIn(SingletonComponent::class) object DispatchersModule { @DefaultDispatcher @Provides fun providesDefaultDispatcher(): CoroutineDispatcher = Dispatchers.Default @IoDispatcher @Provides fun providesIoDispatcher(): CoroutineDispatcher = Dispatchers.IO } IO Dispatcherܳ ઱ੑೞח ௏٘ੑפ׮.
  71. Section #2 Application ߧਤীࢲ CoroutineScopeܳ ࢎਊೞח ߑߨਸ ࢓ಝࠁ੗. ৘ܳ ٜয,

    • DataStore ୡӝച • ૑಴ ࣻ૘ • ௿ۄ਋٘ ߔস CoroutineScope in Application? Link: https://medium.com/androiddevelopers/create-an-application-coroutinescope-using-hilt-dd444e721528
  72. class Example { fun doSomething() { GlobalScope.launch { // X

    /* do something! */ } } } Link: https://medium.com/androiddevelopers/coroutines-patterns-for-work-that-shouldnt-be-cancelled-e26c40f142ad GlobalScopeח పझ౟ܳ য۵ѱ ٜ݅যࢲ ӂ੢ೞ૑ ঋणפ׮.
  73. class Example { fun doSomething() { // androidx.lifecycle:lifecycle-process ProcessLifecycleOwner.get().lifecycleScope.launch {

    /* do something! */ } } } Link: https://medium.com/androiddevelopers/coroutines-patterns-for-work-that-shouldnt-be-cancelled-e26c40f142ad ؀উਵ۽ ProcessLifecycleOwner੉ ੓णפ׮݅,
  74. class Example @Inject constructor( @ApplicationScope private val lifecycleOwner: LifecycleOwner, //

    X ) { fun doSomething() { lifecycleOwner.lifecycleScope.launch { /* do something! */ } } } @Module @InstallIn(SingletonComponent::class) object ApplicationModule { @ApplicationScope @Provides fun providesProcessLifecycleOwner(): LifecycleOwner = ProcessLifecycleOwner.get() } Link: https://developer.android.com/reference/androidx/lifecycle/ProcessLifecycleOwner ݃ଲо૑۽ పझ౟ܳ য۵ѱ ٜ݅য ӂ੢ೞ૑ ঋणפ׮.
  75. Library Internal // androidx.lifecycle:lifecycle-runtime-ktx public val LifecycleOwner.lifecycleScope: LifecycleCoroutineScope get() =

    lifecycle.coroutineScope public val Lifecycle.coroutineScope: LifecycleCoroutineScope get() { while (true) { val existing = mInternalScopeRef.get() as LifecycleCoroutineScopeImpl? if (existing != null) { return existing } val newScope = LifecycleCoroutineScopeImpl( this, SupervisorJob() + Dispatchers.Main.immediate ) if (mInternalScopeRef.compareAndSet(null, newScope)) { newScope.register() return newScope } Link: https://developer.android.com/topic/libraries/architecture/coroutines#lifecyclescope ؀न lifecycleScope ղࠗ ௏٘ܳ ଵҊೞৈ,
  76. @Module @InstallIn(SingletonComponent::class) object DispatchersModule { @ApplicationScope @Singleton @Provides fun providesApplicationCoroutineScope(

    @MainImmediateDispatcher mainImmediateDispatcher: CoroutineDispatcher ): CoroutineScope = CoroutineScope(context = SupervisorJob() + mainImmediateDispatcher) @MainImmediateDispatcher @Provides fun providesMainImmediateDispatcher(): CoroutineDispatcher = Dispatchers.Main.immediate } Application ߧਤ੄ CoroutineScopeܳ ૒੽ ࢤࢿೞח Ѫਸ ӂ੢೤פ׮. Link: https://medium.com/androiddevelopers/create-an-application-coroutinescope-using-hilt-dd444e721528
  77. @Module @InstallIn(SingletonComponent::class) object DispatchersModule { @ApplicationScope @Singleton @Provides fun providesApplicationCoroutineScope(

    @MainImmediateDispatcher mainImmediateDispatcher: CoroutineDispatcher ): CoroutineScope = CoroutineScope(context = SupervisorJob() + mainImmediateDispatcher) @MainImmediateDispatcher @Provides fun providesMainImmediateDispatcher(): CoroutineDispatcher = Dispatchers.Main.immediate } Dispatcherܳ ࢶఖೡ ٸ, Application ١ UI ۽૒ী ઱۽ ࢎਊೠ׮ݶ ࣽࢲ ࠁ੢੉ غח Main.immediateܳ ࢎਊೡ ࣻ ੓Ҋ,
  78. @Module @InstallIn(SingletonComponent::class) object DispatchersModule { @ApplicationScope @Singleton @Provides fun providesApplicationCoroutineScope(

    @DefaultDispatcher defaultDispatcher: CoroutineDispatcher ): CoroutineScope = CoroutineScope(context = SupervisorJob() + defaultDispatcher) @DefaultDispatcher @Provides fun providesDefaultDispatcher(): CoroutineDispatcher = Dispatchers.Default } Background ੘সী ઱۽ ࢎਊೠ׮ݶ Dispatcher ੹ജ੉ ੸ب۾ Defaultܳ ࢎਊೡ ࣻ ੓णפ׮.
  79. @Module @InstallIn(SingletonComponent::class) object DispatchersModule { @ApplicationScope @Singleton @Provides fun providesApplicationCoroutineScope(

    @DefaultDispatcher defaultDispatcher: CoroutineDispatcher ): CoroutineScope = CoroutineScope(context = SupervisorJob() + defaultDispatcher) } class Example @Inject constructor( @ApplicationScope private val applicationScope: CoroutineScope, ) { fun doSomething() { applicationScope.launch { /* do something! */ } } } Qualifier۽ CoroutineScopeܳ ઱ੑೞݶ ؾפ׮.
  80. Section #2 Service ߧਤীࢲ CoroutineScopeܳ ࢎਊೞח ߑߨਸ ࢓ಝࠁ੗. ৘ܳ ٜয,

    • ׮਍۽٘/স۽٘ • ਺ঈ ੤ࢤ • ղ࠺ѱ੉࣌ CoroutineScope in Service?
  81. @Module @InstallIn(ServiceComponent::class) object ServiceModule { @ServiceScope // ??? @ServiceScoped @Provides

    fun providesServiceScope( @MainImmediateDispatcher dispatcher: CoroutineDispatcher ): CoroutineScope = CoroutineScope(context = SupervisorJob() + dispatcher) } @Qualifier @Retention(AnnotationRetention.BINARY) annotation class ServiceScope ૒੽ ࢤࢿೞח ߑߨ੉ ݢ੷ ځয়ܰחؘਃ. Serviceо ઙܐؼ ٸח যڌѱ ஂࣗೡөਃ?
  82. class ExampleActivity : androidx.core.app.ComponentActivity() { private fun doSomething() { lifecycleScope.launch

    { /* do something! */ } } } package androidx.core.app; public class ComponentActivity extends Activity implements LifecycleOwner { ... } ׮ܲ ஹನք౟৬ ࠺Ү೧ࠁݶ, Activityח Lifecycleਸ Ҋ۰ೠ CoroutineScopeܳ ઁҕೞҊ
  83. class ExampleFragment : androidx.fragment.app.Fragment() { private fun doSomething() { lifecycleScope.launch

    { /* do something! */ } viewLifecycleOwner.lifecycleScope.launch { /* do something! */ } } } package androidx.fragment.app; public class Fragment implements LifecycleOwner { @MainThread @NonNull public LifecycleOwner getViewLifecycleOwner() { ... } } Fragmentب Lifecycleਸ Ҋ۰ೠ CoroutineScopeܳ ઁҕ೤פ׮.
  84. class ExampleService : Service() { private fun doSomething() { lifecycleScope.launch

    { // X /* do something! */ } } } package android.app; public abstract class Service extends ContextWrapper { ... } // X ইऔѱب Serviceח LifecycleOwnerܳ ҳഅೞ૑ ঋই, ࢎਊೡ ࣻ হחؘਃ.
  85. class ExampleService : LifecycleService() { private fun doSomething() { lifecycleScope.launch

    { /* do something! */ } } } // androidx.lifecycle:lifecycle-service package androidx.lifecycle; public class LifecycleService extends Service implements LifecycleOwner { ... } Link: https://dagger.dev/hilt/entry-points ؀न LifecycleServiceܳ ੉ਊೞৈ, Lifecycleਸ Ҋ۰ೠ CoroutineScopeܳ ࢎਊೡ ࣻ ੓णפ׮.
  86. Section #2 • Qualifierܳ ੉ਊೞৈ, ׮নೠ CoroutineDispatcherܳ ҳ࠙ೞৈ ઱ੑೡ ࣻ

    ੓׮. • Application ߧਤীࢲח ࢤݺ઱ӝо ೙ਃೠ ҃਋݅ ProcessLifecycleOwnerܳ ࢎਊೞҊ, Coroutines਷ DIܳ ੉ਊೞৈ Custom CoroutineScopeܳ ٜ݅য ࢎਊೞ੗. • উ٘۽੉٘ ೒ۖಬ੄ ҳࢿਃࣗীࢲ ഐ୹ೞח Coroutines਷ Lifecycle-aware CoroutineScopeܳ ੉ਊೞ੗. • Activity, Fragment, Service(=LifecycleService) -> lifecycleScope • ViewModel -> viewModelScope Coroutines Summary Link: https://en.wikipedia.org/wiki/Dependency_injection
  87. Section #2 • Hiltо ઁҕೞ૑ ঋח ҳࢿਃࣗীب EntryPointܳ ੉ਊೞৈ ੄ઓࢿਸ

    ઱ੑೡ ࣻ ੓׮. • Contextী ੽Ӕೡ ࣻ ੓׮ݶ Application ߧਤ੄ ੄ઓࢿਸ ઱ੑೡ ࣻ ੓׮. • ׮নೠ ۄ੉࠳۞ܻ৬ ো҅ೞৈ ഝਊೡ ࣻ ੓׮. • Startup, Glide ١١ Thinking about EntryPoint Link: https://dagger.dev/hilt/entry-points
  88. // Startup: Constructor Injection (X) class ExampleInitializer @Inject constructor( //

    X private val bar: Bar, ) : Initializer<Example> { override fun create(context: Context): Example { ... } } Startupҗ э਷ ۄ੉࠳۞ܻܳ ੉ਊೞ׮ ࠁݶ, ࢤࢿ੗ ઱ੑਸ ೞ૑ ޅೡ ࣻ ੓णפ׮.
  89. // Startup: Field Injection (X) @AndroidEntryPoint // X class ExampleInitializer

    : Initializer<Example> { @Inject lateinit var bar: Bar, override fun create(context: Context): Example { ... } } ੉۠ ҃਋ীח AndroidEntryPointب ૑ਗೞ૑ ঋই ೙٘ ઱ੑب য۵ҳਃ.
  90. // Startup: Alternatives (?) class ExampleInitializer : Initializer<Example> { override

    fun create(context: Context): Example { ... } } ੉ ٸ, Contextী ੽Ӕೡ ࣻ ੓ਵݶ
  91. // Startup: EntryPoint class ExampleInitializer : Initializer<Example> { @EntryPoint @InstallIn(SingletonComponent::class)

    interface ExampleInitializerEntryPoint { fun providesBar(): Bar } override fun create(context: Context): Example { val entryPoint = EntryPointAccessors.fromApplication( context.applicationContext, ExampleInitializerEntryPoint::class.java ) val bar = entryPoint.providesBar() ... } } EntryPointܳ ੉ਊೞৈ, Application ߧਤ੄ ੄ઓࢿਸ ઱ੑೡ ࣻ ੓णפ׮.
  92. // Glide: EntryPoint @GlideModule class ExampleAppGlideModule : AppGlideModule() { @EntryPoint

    @InstallIn(SingletonComponent::class) interface ExampleAppGlideModuleEntryPoint { fun providesBar(): Bar } override fun registerComponents(context: Context, glide: Glide, registry: Registry) { val entryPoint = EntryPointAccessors.fromApplication( context.applicationContext, ExampleAppGlideModuleEntryPoint::class.java ) val bar = entryPoint.providesBar() ... } } ׮ܲ ৘द۽ Glide੄ ௏٘ੑפ׮.
  93. Section #2 • Composeח ࢚కо ղ۰оҊ ੉߮౟о ৢۄоח ױߑೱ ؘ੉ఠ

    ൒ܴ(UDF) ಁఢਸ ӂ੢ೠ׮. • ݽٚ ੄ઓࢿਸ Composableী ݒѐ߸ࣻ۽ ੹׳ೡ ೙ਃח হب۾, CompositionLocalਸ ઁҕೠ׮. ੉۞ݶ ౠ੿ Composable ҅க ղীࢲ݅ زੌೠ ੋझఢझܳ ࢎਊೡ ࣻ ੓׮. • Ӓؘ۠ জ ੹୓ীࢲ زੌೠ ੋझఢझܳ ࢎਊೞѢա ౠ੿ Composableীࢲ݅ ࢎਊೠ׮ݶ? Compose with EntryPoint Link: https://developer.android.com/jetpack/compose/state#state-hoisting
  94. // Option 1: State Hoisting Parents GrandParents Children GrandChildren Bar

    Bar Bar Bar Link: https://developer.android.com/jetpack/compose/state#state-hoisting ৘द۽ GrandChildrenীࢲ Barܳ ࢎਊೞ۰ݶ, пп੄ Composable ೣࣻܳ Ѣ୛ ੹׳ೡ ࣻ ੓णפ׮.
  95. // Option 1: State Hoisting @AndroidEntryPoint class ExampleActivity : Activity()

    { @Inject lateinit var bar: Bar override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { GrandParents(bar = bar) } } } Link: https://developer.android.com/jetpack/compose/state#state-hoisting ௏٘۽ח, Activityী ઱ੑ߉਷ Barܳ GrandParentsী ੹׳ೞҊ
  96. // Option 1: State Hoisting @Composable fun GrandParents(bar: Bar) {

    Parents(bar = bar) } @Composable fun Parents(bar: Bar) { Children(bar = bar) } @Composable fun Children(bar: Bar) { GrandChildren(bar = bar) } @Composable fun GrandChildren(bar: Bar) { // Use bar } Link: https://developer.android.com/jetpack/compose/state#state-hoisting пп੄ Composableਸ Ѣ୛ GrandChildrenө૑ ੹׳ೡ ࣻ ੓णפ׮.
  97. // Option 1: State Hoisting @Composable fun GrandParents(bar: Bar) {

    Parents(bar = bar) } @Composable fun Parents(bar: Bar) { Children(bar = bar) } @Composable fun Children(bar: Bar) { GrandChildren(bar = bar) } @Composable fun GrandChildren(bar: Bar) { // Use bar } Link: https://developer.android.com/jetpack/compose/state#state-hoisting Ӓؘ۠ GrandChildrenীࢲ݅ ࢎਊೞחؘ, ݽٚ Composableਸ Ѣ୛оח Ѫ੉ ઑӘ җ೧ࠁ੉૑ ঋաਃ?
  98. // Option 2: CompositionLocal Parents GrandParents Children GrandChildren Bar Link:

    https://developer.android.com/jetpack/compose/compositionlocal LocalBar Bar CompositionLocalਸ ੉ਊೞৈ ѐࢶೡ ࣻ ੓णפ׮.
  99. // Option 2: CompositionLocal @AndroidEntryPoint class ExampleActivity : Activity() {

    @Inject lateinit var bar: Bar override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { CompositionLocalProvider(LocalBar provides bar) { GrandParents() } } } } val LocalBar = staticCompositionLocalOf<Bar> { error("...") } Link: https://developer.android.com/jetpack/compose/compositionlocal ௏٘۽ח, Activityী ઱ੑ ߉਷ Barܳ LocalBar۽ ઁҕೞҊ
  100. // Option 2: CompositionLocal @Composable fun GrandParents() { Parents() }

    @Composable fun Parents() { Children() } @Composable fun Children() { GrandChildren() } @Composable fun GrandChildren() { val bar: Bar = LocalBar.current // Use bar } Link: https://developer.android.com/jetpack/compose/compositionlocal GrandChildrenীࢲ LocalBarܳ ా೧, Barܳ оઉоݶ ؾפ׮.
  101. // Option 2: CompositionLocal @AndroidEntryPoint class ExampleActivity : Activity() {

    @Inject lateinit var bar: Bar @Inject lateinit var foo: Foo override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { CompositionLocalProvider( LocalBar provides bar, LocalFoo provides foo, ) { ... } } } } Link: https://developer.android.com/jetpack/compose/compositionlocal#alternatives Ӓؘ۠ CompositionLocalܳ ੄بೠ؀۽ ࢎਊೠ Ѫ੉ ݏਸөਃ? ӒܻҊ ઱ੑ೧ঠ ೞח ೦ݾ੉ ੼੼ טযդ׮ݶ ҡଳਸөਃ?
  102. // Option 3: EntryPoint Parents GrandParents Children GrandChildren Bar Link:

    https://dagger.dev/hilt/entry-points য૵ݶ EntryPointо ೞա੄ ؀উ੉ ؼ ࣻب ੓ਸ Ѫ эणפ׮.
  103. // Option 3: @AndroidEntryPoint class ExampleActivity : Activity() { //

    @Inject lateinit var bar: Bar override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { GrandParents() } } } Link: https://dagger.dev/hilt/entry-points ௏٘۽ח, ؊ ੉࢚ Activityী ઱ੑ߉ਸ ೙ਃо হणפ׮.
  104. // Option 3: @Composable fun GrandParents() { Parents() } @Composable

    fun Parents() { Children() } @Composable fun Children() { GrandChildren() } @Composable fun GrandChildren() { val bar: Bar = rememberBar() // Use bar } Link: https://dagger.dev/hilt/entry-points CompositionLocal୊ۢ GrandChildrenীࢲ ߄۽ ଵઑೡ ࣻ ੓णפ׮.
  105. // Option 3: @Composable private fun rememberBar(): Bar { val

    context = LocalContext.current return remember { val entryPoint = EntryPointAccessors.fromApplication( context.applicationContext, ExampleEntryPoint::class.java, ) entryPoint.providesBar() } } @EntryPoint @InstallIn(SingletonComponent::class) interface ExampleEntryPoint { fun providesBar(): Bar } Link: https://dagger.dev/hilt/entry-points ߑߨ਷ LocalContextܳ ੉ਊ೧, Application ߧਤ੄ ੄ઓࢿਸ ઱ੑೞח Ѫੑפ׮.
  106. DIܳ ࢎਊೞ۰ח ݾ੸ী ٮۄ, Dagger Hilt ࢎਊߑߨਸ Ҋ޹೧ࠁ੗. • ୭؀ೠ

    ೒ۖಬ ੄ઓࢿਸ ઴੉੗. (ex. WorkManager) • উ٘۽੉٘ ҳࢿਃࣗীࢲח Lifecycle-aware Coroutinesਸ ࢎਊೞ੗. • EntryPointܳ ੉ਊೞৈ, ۄ੉࠳۞ܻ ҙ۲ ௏٘ীب ੄ઓࢿ ઱ੑ੉ оמೞ׮. Wrap-Up
  107. Sungyong An NAVER WEBTOON Android GDE / ? Thank You

    Sungyong An NAVER WEBTOON Android GDE / @fornewid Slide Link: https://speakerdeck.com/fornewid