Android Developers에서 코루틴 디스패처를 주입 하는 것을 권장한다고 들었습니다.
왜 그런걸까요?
크게 두가지 입니다.
테스트할때 디스패처만 테스트 디스패처로 주입 받아서 테스트하면 좋겠죠?
그리고 스코프를 일괄적으로 관리하여
생성된 코루틴을 일관된 스코프에서 관리 할 수있게 해줍니다.
그럼 이제 어떻게 주입하는지 살펴봅시다.
@InstallIn(SingletonComponent::class)
@Module
object CoroutinesScopesModule {
@Singleton
@Provides
fun providesCoroutineScope(): CoroutineScope {
return CoroutineScope(SupervisorJob() + Dispatchers.Default)
}
}
코루틴 스코프를 반환하는 모듈을 만들어 줍시다.
@Retention(AnnotationRetention.RUNTIME)
@Qualifier
annotation class DefaultDispatcher
@Retention(AnnotationRetention.RUNTIME)
@Qualifier
annotation class IoDispatcher
@Retention(AnnotationRetention.RUNTIME)
@Qualifier
annotation class MainDispatcher
@Retention(AnnotationRetention.BINARY)
@Qualifier
annotation class MainImmediateDispatcher
주입을 받는데 다 똑같이 CoroutineDispatcher로 유형이 똑같죠?
그럴때를 위한 Qualifier를 만들어 줍니다.
@InstallIn(SingletonComponent::class)
@Module
object CoroutinesDispatchersModule {
@DefaultDispatcher
@Provides
fun providesDefaultDispatcher(): CoroutineDispatcher = Dispatchers.Default
@IoDispatcher
@Provides
fun providesIoDispatcher(): CoroutineDispatcher = Dispatchers.IO
@MainDispatcher
@Provides
fun providesMainDispatcher(): CoroutineDispatcher = Dispatchers.Main
@MainImmediateDispatcher
@Provides
fun providesMainImmediateDispatcher(): CoroutineDispatcher = Dispatchers.Main.immediate
}
이제 주입할 dispatcher의 모듈들을 만들어 줍시다.
@InstallIn(SingletonComponent::class)
@Module
object CoroutinesScopesModule {
@Singleton
@Provides
fun providesCoroutineScope(
@DefaultDispatcher defaultDispatcher: CoroutineDispatcher
): CoroutineScope = CoroutineScope(SupervisorJob() + defaultDispatcher)
}
처음에 만들었던 스코프 모듈에서 하드 코딩된 디스패처를 제거하고
싱글톤 디스패처를 주입하도록 합시다!
이렇게 되면 디스패처를 통해 스코프를 일관되게 관리 할 수 있습니다.
@Retention(AnnotationRetention.RUNTIME)
@Qualifier
annotation class ApplicationScope
@InstallIn(SingletonComponent::class)
@Module
object CoroutinesScopesModule {
@Singleton
@ApplicationScope
@Provides
fun providesCoroutineScope(
@DefaultDispatcher defaultDispatcher: CoroutineDispatcher
): CoroutineScope = CoroutineScope(SupervisorJob() + defaultDispatcher)
}
어플리케이션 스코프를 추가하면 딱히 동작은 변하지 않지만 가독성에 도움이 됩니다
이렇게 하면 어떤 스코프인지 바로 알 수 있겠죠?
@TestInstallIn(
components = [SingletonComponent::class],
replaces = [CoroutinesDispatchersModule::class]
)
@Module
object TestCoroutinesDispatchersModule {
@DefaultDispatcher
@Provides
fun providesDefaultDispatcher(): CoroutineDispatcher =
AsyncTask.THREAD_POOL_EXECUTOR.asCoroutineDispatcher()
@IoDispatcher
@Provides
fun providesIoDispatcher(): CoroutineDispatcher =
AsyncTask.THREAD_POOL_EXECUTOR.asCoroutineDispatcher()
@MainDispatcher
@Provides
fun providesMainDispatcher(): CoroutineDispatcher = Dispatchers.Main
}
TestInstallIn... 이건 제가 Hilt Test 포스팅 할 때 다뤘던 내용이죠?
[Android] Hilt Test와 함께 알아보는 안드로이드 간단 TDD!
테스트에서 사용할 Dispatcher Module을 교체합니다.
그러면 앱 모듈과 별개로 테스트 모듈만 사용해서 테스트 할 수 있게 됩니다!
지금까지 저는 거의 디스패처를 하드코딩해왔는데
앞으로는 주입 받아서 사용해야겠네요
테스트를 생각하나 일관성을 생각하나 놓칠게 없는 것 같아요!
https://medium.com/androiddevelopers/create-an-application-coroutinescope-using-hilt-dd444e721528
이번 글은 해당 포스트의 내용을 제가 알아보기 쉽게 정리한 포스팅에 불과합니다.
해당 포스팅이 훨씬 정확하고 자세하니 궁금하시다면 한번 보러가세요.