Slide 1

Slide 1 text

Dagger Hilt۽ ੄ઓࢿ ઱ੑೞӝ Android

Slide 2

Slide 2 text

Sungyong An NAVER WEBTOON Android GDE @fornewid

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

Intro ੄ઓࢿ ઱ੑ(DI)਷ ೞա੄ ё୓о ׮ܲ ё୓੄ ੄ઓࢿਸ ઁҕೞח ӝߨ੉׮. ੄ઓࢿ ઱ੑ੄ ੄بח ё୓੄ ࢤࢿҗ ࢎਊ੄ ҙबਸ ܻ࠙ೞח Ѫ੉׮. Dependency Injection? Link: https://en.wikipedia.org/wiki/Dependency_injection

Slide 6

Slide 6 text

// 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ਸ ࢤࢿೞח ௏٘ੑפ׮.

Slide 7

Slide 7 text

// 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ਸ ੹׳ೞѢա,

Slide 8

Slide 8 text

// 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ਸ ࢤࢿೞৈ ೙٘ ઱ੑਵ۽ ੹׳೤פ׮.

Slide 9

Slide 9 text

Intro DI੄ ਗ஗ਸ ٮܰݶ ഴܯೠ জ ইఃఫ୊ܳ ਤೠ ష؀ܳ ݃۲ೡ ࣻ ੓׮. • ௏٘ ੤ࢎਊ оמ • ܻಂష݂ ಞ੄ࢿ • పझ౟ ಞ੄ࢿ Dependency Injection ੉੼? Link: https://en.wikipedia.org/wiki/Dependency_injection

Slide 10

Slide 10 text

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 ࢶఖೠ ੉ਬ? ૑ࣘоמࢿ …

Slide 11

Slide 11 text

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 💯

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

“Hiltܳ ੉ਊೞৈ Android জী ੄ઓࢿ ઱ੑ ಁఢਸ ҳഅೞغ, ݾ੸ਸ ஂೡ ݅ఀ݅ ੸׼൤ ࢎਊೞח ߑߨਸ Ҋ޹೧ ࠁ੗.” ݾ಴

Slide 15

Slide 15 text

Hiltо ઁҕೞח জী ੄ઓࢿ ઱ੑೞח ߑߨਸ ঌইࠄ׮. Jetpack ۄ੉࠳۞ܻ৬ োزغח ࠗ࠙ب рױ൤ ࢓ಝࠄ׮. ݾ੸ী ݏѱ, জীࢲ Hiltܳ ࢎਊೞח ഋకܳ Ҋ޹೧ ࠄ׮. ӝࠄ о੉٘ࠁ׮ ؊ ࠂ੟ೞѱ ࢎਊೞח Ѫ੉ ա਷ ࠗ࠙җ য়൤۰ ࢎਊೞ૑ ঋח Ѫ੉ ա਷ ࠗ࠙ ١ਸ ࢤп೧ ࠄ׮. Dagger Hilt Thinking Usages ݾର

Slide 16

Slide 16 text

Dependency Injection with Dagger Hilt Section #1 Dagger Hiltܳ ੉ਊೞৈ ੄ઓࢿ ઱ੑೞӝ

Slide 17

Slide 17 text

// 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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

class ExampleApplication : Hilt_ExampleApplication() public abstract class Hilt_ExampleApplication extends Application implements ... { @CallSuper @Override public void onCreate() { hiltInternalInject(); super.onCreate(); } ... } Generated Gradle ೒۞Ӓੋਸ ੉ਊೞݶ ࢚ࣘਸ ా೧

Slide 21

Slide 21 text

public final class ExampleApplication_MembersInjector implements MembersInjector { private final Provider barProvider; public ExampleApplication_MembersInjector(Provider 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 ੄ઓࢿب ઱ੑೡ ࣻ ੓णפ׮.

Slide 22

Slide 22 text

@AndroidEntryPoint class ExampleActivity : Activity() { @Inject lateinit var bar: Bar override fun onCreate() { super.onCreate() // Use bar } } (2) Activityח AndroidEntryPointܳ ੉ਊೞৈ, Field Injection੉ оמ೤פ׮.

Slide 23

Slide 23 text

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 ݃ଲо૑۽ ࢚ࣘਸ ా೧, ੄ઓࢿਸ ઱ੑ೤פ׮.

Slide 24

Slide 24 text

@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ب زੌ೤פ׮.

Slide 25

Slide 25 text

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 ݃ଲо૑۽ ࢚ࣘਸ ా೧, ੄ઓࢿਸ ઱ੑ೤פ׮.

Slide 26

Slide 26 text

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ܳ ੉ਊೞৈ, ੄ઓࢿਸ ઱ੑೡ ࣻ ੓णפ׮.

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

@Module @InstallIn(SingletonComponent::class) object ExampleModule { @Provides fun providesBar(foo: Foo): Bar = Bar(foo) @Provides fun providesFoo(): Foo = Foo() } (5) InstallInਸ ੉ਊೞৈ, Moduleਸ ࢸ஖ೞ۰ח Componentܳ ੿੄೤פ׮.

Slide 29

Slide 29 text

Section #1 ׮নೠ উ٘۽੉٘ ҳࢿਃࣗ੄ ࣻݺ ઱ӝী ੗زਵ۽ ా೤غח ӝࠄ ઁҕ Componentо ੓णפ׮. п ҳࢿ ਃࣗ੄ ࣻݺী ؀ೠ ߄ੋ٬ ߧਤܳ ૑੿ೞחؘ ࢎਊغח Scope Annotation੉ ੓णפ׮. Component Link: https://dagger.dev/hilt/components

Slide 30

Slide 30 text

@Module @InstallIn(SingletonComponent::class) object ExampleModule { @Provides fun providesBar(foo: Foo): Bar = Bar(foo) @Provides fun providesFoo(): Foo = Foo() } Foo Bar (6) Providesܳ ੉ਊೞৈ, ੄ઓࢿਸ ઁҕೡ ࣻ ੓णפ׮.

Slide 31

Slide 31 text

public final class ExampleModule_ProvidesFooFactory implements Factory { @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 ௿ېझо ੗ز ࢤࢿؾפ׮.

Slide 32

Slide 32 text

public final class ExampleModule_ProvidesBarFactory implements Factory { private final Provider fooProvider; public ExampleModule_ProvidesBarFactory(Provider fooProvider) { this.fooProvider = fooProvider; } @Override public Bar get() { return providesBar(fooProvider.get()); } public static ExampleModule_ProvidesBarFactory create(Provider fooProvider) { return new ExampleModule_ProvidesBarFactory(fooProvider); } public static Bar providesBar(Foo foo) { return Preconditions.checkNotNullFromProvides(ExampleModule.INSTANCE.providesBar(foo)); } } Generated

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

@Module @InstallIn(SingletonComponent::class) object ExampleModule { // unscoped @Provides fun providesBar(foo: Foo): Bar = BarImpl(foo) @Singleton @Provides fun providesFoo(): Foo = FooImpl() } (8) Scopeܳ ૑੿ೞݶ, ೧׼ Component੄ ࣻݺ੉ ՘զ ٸө૑ ਬ૑ؾפ׮.

Slide 35

Slide 35 text

private static final class SingletonCImpl extends ... { private Provider providesFooProvider; private SingletonCImpl() { this.providesFooProvider = DoubleCheck.provider( () -> ExampleModule_ProvidesFooFactory.providesFoo() ); } public Bar providesBar() { return ExampleModule_ProvidesBarFactory .providesBar((Foo)this.providesFooProvider.get()) .bar(); } } Generated Scopeо ૑੿غ૑ ঋਵݶ, ݒߣ ࢤࢿ೤פ׮.

Slide 36

Slide 36 text

@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 { ... }

Slide 37

Slide 37 text

private static final class SingletonCImpl extends ... { private Provider fooImplProvider; private Provider 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 ௿ېझо ࢤࢿغ૑ ঋणפ׮.

Slide 38

Slide 38 text

Section #1 Dagger Hilt۽ ViewModelী ੄ઓࢿਸ ઱ੑೡ ࣻ ੓णפ׮. Dagger Hilt۽ Workerী ੄ઓࢿਸ ઱ੑೡ ࣻ ੓णפ׮. ViewModel WorkManager With Jetpack Libraries

Slide 39

Slide 39 text

@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ܳ ࢎਊೞৈ ੄ઓࢿਸ ઱ੑ೤פ׮.

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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ܳ ࢎਊ೤פ׮.

Slide 42

Slide 42 text

@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ী ੽Ӕೞח ௏٘ੑפ׮.

Slide 43

Slide 43 text

package androidx.lifecycle.viewmodel.compose @Composable public inline fun 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ਸ ੉ਊೞח ߑधੑפ׮.

Slide 44

Slide 44 text

package androidx.lifecycle.viewmodel.compose public object LocalViewModelStoreOwner { private val LocalViewModelStoreOwner = compositionLocalOf { null } public val current: ViewModelStoreOwner? @Composable get() = LocalViewModelStoreOwner.current ?: LocalView.current.findViewTreeViewModelStoreOwner() } Library Internal LocalViewܳ ా೧, ViewModelStoreOwnerী ੽Ӕ೤פ׮.

Slide 45

Slide 45 text

package androidx.activity; public class ComponentActivity extends androidx.core.app.ComponentActivity implements ViewModelStoreOwner { private void initViewTreeOwners() { ... ViewTreeViewModelStoreOwner.set(getWindow().getDecorView(), this); ... } } Library Internal ѾҴ ViewModelStoreOwnerܳ ੉ਊೞৈ,

Slide 46

Slide 46 text

private fun ViewModelStoreOwner.get( javaClass: Class, 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ী ੽Ӕ೤פ׮.

Slide 47

Slide 47 text

// 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ח ۄ੉࠳۞ܻܳ ୶о ࢸ஖೧ঠ ೤פ׮.

Slide 48

Slide 48 text

@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ܳ ੉ਊೞৈ ࢤࢿ੗ী ӝࠄ ݒѐ߸ࣻܳ ઱ੑ೤פ׮.

Slide 49

Slide 49 text

public final class ExampleWorker_Factory { private final Provider exampleProvider; public ExampleWorker_Factory(Provider 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৬

Slide 50

Slide 50 text

public interface ExampleWorker_AssistedFactory extends WorkerAssistedFactory {} 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 create( ExampleWorker_Factory delegateFactory) { return InstanceFactory.create(new ExampleWorker_AssistedFactory_Impl(delegateFactory)); } } Generated ӝࠄ ݒѐ߸ࣻܳ ୶оೞח Factory. 2о૑о ࢤࢿؾפ׮.

Slide 51

Slide 51 text

public interface WorkerAssistedFactory { @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ਵ۽ ޘੑפ׮.

Slide 52

Slide 52 text

@Module @InstallIn(SingletonComponent.class) abstract class WorkerFactoryModule { @NonNull @Multibinds abstract Map> workerFactoriesMap(); @NonNull @Provides static HiltWorkerFactory provideFactory(@NonNull Map>> workerFactories) { return new HiltWorkerFactory(workerFactories); } } Generated ݽٚ Worker੄ Providerח HiltWorkerFactoryী ੹׳ؾפ׮.

Slide 53

Slide 53 text

public final class HiltWorkerFactory extends androidx.work.WorkerFactory { private final Map>> mWorkerFactories; ... @Nullable @Override public ListenableWorker createWorker(@NonNull Context appContext, @NonNull String workerClassName, @NonNull WorkerParameters workerParameters) { Provider> factoryProvider = mWorkerFactories.get(workerClassName); if (factoryProvider == null) { return null; } return factoryProvider.get().create(appContext, workerParameters); } } Library Internal п Providerח Workerܳ पઁ۽ ࢤࢿ೧ঠ ೡ ٸ ࢎਊؾפ׮.

Slide 54

Slide 54 text

@HiltAndroidApp class ExampleApplication : Application(), Configuration.Provider { @Inject lateinit var workerFactory: HiltWorkerFactory override fun getWorkManagerConfiguration() = Configuration.Builder() .setWorkerFactory(workerFactory) .build() } val exampleWorkRequest: WorkRequest = OneTimeWorkRequestBuilder().build() WorkManager.getInstance(context).enqueue(exampleWorkRequest) (3) HiltWorkerFactoryܳ Applicationী ઱ੑ ߉ই, WorkManagerܳ ୡӝചೞݶ ࢸ੿੉ ৮ܐؾפ׮.

Slide 55

Slide 55 text

Thinking Usages about Dagger Hilt Section #2 Dagger Hilt ࢎਊߑߨী ؀೧ ࢤп೧ࠁӝ

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

// Problem 1: val context: Context = ... // Where this from? val request = OneTimeWorkRequestBuilder() .addTag(ExampleWorker.TAG) .build() WorkManager.getInstance(context).enqueue(request) WorkManagerܳ ࢎਊೞ۰ݶ Contextо ೙ਃೞ׮. WorkManager Context

Slide 59

Slide 59 text

@Module @InstallIn(SingletonComponent::class) object TasksModule { @Singleton @Provides fun provideWorkManager( @ApplicationContext context: Context, ): WorkManager { return WorkManager.getInstance(context) } } DIܳ ੉ਊೞৈ, Context ੄ઓࢿਸ ऀӡ ࣻ ੓Ҋ WorkManager

Slide 60

Slide 60 text

@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

Slide 61

Slide 61 text

// Problem 2: @AndroidEntryPoint class ExampleActivity : Activity() { @Inject lateinit var workManager: WorkManager } @HiltViewModel class ExampleViewModel @Inject constructor( private val workManager: WorkManager ) : ViewModel() val request = OneTimeWorkRequestBuilder() .addTag(ExampleWorker.TAG) .build() workManager.enqueue(request) ೞ૑݅ Worker, WorkManager ١ ೒ۖಬ ௿ېझী ੄ઓࢿਸ ыѱ ؾפ׮. WorkManager Example Activity Example Worker

Slide 62

Slide 62 text

@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() .addTag(ExampleWorker.TAG) .build() workManager.enqueue(request) } } DIܳ ੉ਊೞৈ, ز੘਷ زੌೞ૑݅ WorkManager Example Worker Example Tasks

Slide 63

Slide 63 text

@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

Slide 64

Slide 64 text

// 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੄ ز੘җ ࠺ૉפझ ۽૒੉ ೠؘ ࢴৈ ੓णפ׮.

Slide 65

Slide 65 text

@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ܳ ੉ਊೞৈ, ࠺ૉפझ ۽૒݅ ܻ࠙ೞৈ

Slide 66

Slide 66 text

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੄ ৉ೡਸ ୭ࣗചೡ ࣻ ੓णפ׮.

Slide 67

Slide 67 text

Section #2 పझ౟ܳ Ҋ۰ೞৈ, CoroutineDispatcherܳ ૒੽ ੑ۱ೞ૑ ঋҊ ੄ઓࢿ ઱ੑೞৈ ࢎਊೞח ߑߨਸ ࢓ಝࠄ׮. Qualifierܳ ੉ਊೞৈ, ׮নೠ CoroutineDispatcherܳ ҳ ࠙ೞৈ ઱ੑೡ ࣻ ੓׮. জীࢲ ࢎਊೞӝ ੸׼ೠ CoroutineScopeܳ ࢓ಝࠁ੗. ౠ൤, Application ژח Service ߧਤ ղীࢲ ௏ܖ౯ਸ ҙܻ ೞח ߑߨਸ ঌইࠁҊ, Hilt۽ ੄ઓࢿ ઱ੑೞח Ѫ੉ о੢ જ਷ ߑߨੋ૑ Ҋ޹೧ ࠁ੗. CoroutineDispatcher CoroutineScope Thinking about Coroutines

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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ܳ ੉ਊೠ ௏٘ੑפ׮.

Slide 71

Slide 71 text

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 // ??? } Ӓؘ۠ ׮ܲ ਬഋ੉ ೙ਃೞ׮ݶ যڌѱ ೧ঠ ೡөਃ?

Slide 72

Slide 72 text

@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

Slide 73

Slide 73 text

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ܳ ઱ੑೞח ௏٘ੑפ׮.

Slide 74

Slide 74 text

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ܳ ઱ੑೞח ௏٘ੑפ׮.

Slide 75

Slide 75 text

Section #2 Application ߧਤীࢲ CoroutineScopeܳ ࢎਊೞח ߑߨਸ ࢓ಝࠁ੗. ৘ܳ ٜয, • DataStore ୡӝച • ૑಴ ࣻ૘ • ௿ۄ਋٘ ߔস CoroutineScope in Application? Link: https://medium.com/androiddevelopers/create-an-application-coroutinescope-using-hilt-dd444e721528

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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੉ ੓णפ׮݅,

Slide 78

Slide 78 text

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 ݃ଲо૑۽ పझ౟ܳ য۵ѱ ٜ݅য ӂ੢ೞ૑ ঋणפ׮.

Slide 79

Slide 79 text

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 ղࠗ ௏٘ܳ ଵҊೞৈ,

Slide 80

Slide 80 text

@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

Slide 81

Slide 81 text

@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ܳ ࢎਊೡ ࣻ ੓Ҋ,

Slide 82

Slide 82 text

@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ܳ ࢎਊೡ ࣻ ੓णפ׮.

Slide 83

Slide 83 text

@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ܳ ઱ੑೞݶ ؾפ׮.

Slide 84

Slide 84 text

Section #2 Service ߧਤীࢲ CoroutineScopeܳ ࢎਊೞח ߑߨਸ ࢓ಝࠁ੗. ৘ܳ ٜয, • ׮਍۽٘/স۽٘ • ਺ঈ ੤ࢤ • ղ࠺ѱ੉࣌ CoroutineScope in Service?

Slide 85

Slide 85 text

@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о ઙܐؼ ٸח যڌѱ ஂࣗೡөਃ?

Slide 86

Slide 86 text

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ܳ ઁҕೞҊ

Slide 87

Slide 87 text

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ܳ ઁҕ೤פ׮.

Slide 88

Slide 88 text

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

Slide 89

Slide 89 text

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ܳ ࢎਊೡ ࣻ ੓णפ׮.

Slide 90

Slide 90 text

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

Slide 91

Slide 91 text

Section #2 • Hiltо ઁҕೞ૑ ঋח ҳࢿਃࣗীب EntryPointܳ ੉ਊೞৈ ੄ઓࢿਸ ઱ੑೡ ࣻ ੓׮. • Contextী ੽Ӕೡ ࣻ ੓׮ݶ Application ߧਤ੄ ੄ઓࢿਸ ઱ੑೡ ࣻ ੓׮. • ׮নೠ ۄ੉࠳۞ܻ৬ ো҅ೞৈ ഝਊೡ ࣻ ੓׮. • Startup, Glide ١١ Thinking about EntryPoint Link: https://dagger.dev/hilt/entry-points

Slide 92

Slide 92 text

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

Slide 93

Slide 93 text

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

Slide 94

Slide 94 text

// Startup: Alternatives (?) class ExampleInitializer : Initializer { override fun create(context: Context): Example { ... } } ੉ ٸ, Contextী ੽Ӕೡ ࣻ ੓ਵݶ

Slide 95

Slide 95 text

// Startup: EntryPoint class ExampleInitializer : Initializer { @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 ߧਤ੄ ੄ઓࢿਸ ઱ੑೡ ࣻ ੓णפ׮.

Slide 96

Slide 96 text

// 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੄ ௏٘ੑפ׮.

Slide 97

Slide 97 text

Section #2 • Composeח ࢚కо ղ۰оҊ ੉߮౟о ৢۄоח ױߑೱ ؘ੉ఠ ൒ܴ(UDF) ಁఢਸ ӂ੢ೠ׮. • ݽٚ ੄ઓࢿਸ Composableী ݒѐ߸ࣻ۽ ੹׳ೡ ೙ਃח হب۾, CompositionLocalਸ ઁҕೠ׮. ੉۞ݶ ౠ੿ Composable ҅க ղীࢲ݅ زੌೠ ੋझఢझܳ ࢎਊೡ ࣻ ੓׮. • Ӓؘ۠ জ ੹୓ীࢲ زੌೠ ੋझఢझܳ ࢎਊೞѢա ౠ੿ Composableীࢲ݅ ࢎਊೠ׮ݶ? Compose with EntryPoint Link: https://developer.android.com/jetpack/compose/state#state-hoisting

Slide 98

Slide 98 text

// 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 ೣࣻܳ Ѣ୛ ੹׳ೡ ࣻ ੓णפ׮.

Slide 99

Slide 99 text

// 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ী ੹׳ೞҊ

Slide 100

Slide 100 text

// 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ө૑ ੹׳ೡ ࣻ ੓णפ׮.

Slide 101

Slide 101 text

// 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ਸ Ѣ୛оח Ѫ੉ ઑӘ җ೧ࠁ੉૑ ঋաਃ?

Slide 102

Slide 102 text

// Option 2: CompositionLocal Parents GrandParents Children GrandChildren Bar Link: https://developer.android.com/jetpack/compose/compositionlocal LocalBar Bar CompositionLocalਸ ੉ਊೞৈ ѐࢶೡ ࣻ ੓णפ׮.

Slide 103

Slide 103 text

// 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 { error("...") } Link: https://developer.android.com/jetpack/compose/compositionlocal ௏٘۽ח, Activityী ઱ੑ ߉਷ Barܳ LocalBar۽ ઁҕೞҊ

Slide 104

Slide 104 text

// 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ܳ оઉоݶ ؾפ׮.

Slide 105

Slide 105 text

// 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ܳ ੄بೠ؀۽ ࢎਊೠ Ѫ੉ ݏਸөਃ? ӒܻҊ ઱ੑ೧ঠ ೞח ೦ݾ੉ ੼੼ טযդ׮ݶ ҡଳਸөਃ?

Slide 106

Slide 106 text

// Option 3: EntryPoint Parents GrandParents Children GrandChildren Bar Link: https://dagger.dev/hilt/entry-points য૵ݶ EntryPointо ೞա੄ ؀উ੉ ؼ ࣻب ੓ਸ Ѫ эणפ׮.

Slide 107

Slide 107 text

// 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ী ઱ੑ߉ਸ ೙ਃо হणפ׮.

Slide 108

Slide 108 text

// 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ীࢲ ߄۽ ଵઑೡ ࣻ ੓णפ׮.

Slide 109

Slide 109 text

// 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 ߧਤ੄ ੄ઓࢿਸ ઱ੑೞח Ѫੑפ׮.

Slide 110

Slide 110 text

DIܳ ࢎਊೞ۰ח ݾ੸ী ٮۄ, Dagger Hilt ࢎਊߑߨਸ Ҋ޹೧ࠁ੗. • ୭؀ೠ ೒ۖಬ ੄ઓࢿਸ ઴੉੗. (ex. WorkManager) • উ٘۽੉٘ ҳࢿਃࣗীࢲח Lifecycle-aware Coroutinesਸ ࢎਊೞ੗. • EntryPointܳ ੉ਊೞৈ, ۄ੉࠳۞ܻ ҙ۲ ௏٘ীب ੄ઓࢿ ઱ੑ੉ оמೞ׮. Wrap-Up

Slide 111

Slide 111 text

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