SlideShare a Scribd company logo
1 of 20
Download to read offline
발표자 : 이상수(vviprogrammer@gmail.com) (2022-06)
DI(Dependency Injection)
With Dagger-Hilt
DI 란?
DI = Dependency Injection = 의존성(종속성) 주입
• 한 클래스가 다른 클래스에 대한 참조가 필요할 때
• Ex) Car 클래스에서 Engine 클래스에 대한 참조가 필수 일때, 의존성을 가지게 된다
class Engine() {}
class Car {
private val engine = Engine() // 의존성
}
DI 란?
클래스가 필요한 의존성(인스턴스)을 얻는 세 가지 방법
1. 필요한 클래스 인스턴스 직접 생성 및 초기화
2. 다른 곳으로 부터 끌어오기 (Ex. Context 게터, getSystemService() 등)
3. 파라미터로 제공 받기 (생성자나 함수 등 에서 필요한 의존성을 전달 받기)
DI 란?
DI(의존성 주입) 을 하지 않는 코드
class Car {
private val engine = Engine()
fun start() {
engine.start()
}
}
fun main(args: Array) {
val car = Car()
car.start()
}
• Car와 Engine은 강하게 커플링 됨
• 테스트가 어려움 (*Test Double 등)
* Test Double : 테스트를 진행하기 어려운 경우 이를 대신해 테스트를 진행할 수 있도록 만들어주는 객체를 말한다.
DI 란?
DI(의존성 주입) 을 사용한 코드
class Car(private val engine: Engine) {
fun start() {
engine.start()
}
}
fun main(args: Array) {
val engine = Engine()
val car = Car(engine)
car.start()
}
• 재사용성 ⬆ (Car 클래스)
• Ex) ElectricEngine
• 테스트 쉬움
• Ex) FakeEngine
DI 란?
Android 에서 주로 사용하는 2가지 DI 방법
1. 생성자 주입(Constructor Injection)
2. 필드 주입(Field Injection)(or Setter Injection)
class Car {
lateinit var engine: Engine
fun start() {
engine.start()
}
}
fun main(args: Array) {
val car = Car()
car.engine = Engine() // 필드 주입
car.start()
}
Automated dependency injection
수동 의존성 주입의 문제점
• 큰 프로젝트에서 올바른 DI 를 해주기 위해서는 많은 양의 boilerplate code 필요
• 앱의 수명 주기를 관리하는 지정 컨테이너를 직접 작성해야하고 유지해야함
Automated dependency injection
의존성 주입 라이브러리
• 의존성 생성과 제공 프로세스를 자동화 하는 라이브러리
• 런타임에 의존성을 주입하는 리플렉션 기반 솔루션
• 컴파일 타임에 의존성을 연결하는 코드를 생성하는 정적 솔루션
• Google 의 Dagger
• Java, Kotlin 및 Android 용 DI로 널리 사용
• 완전 정적 컴파일 타임 DI로 리플렉션 기반 솔루션(Guice 등)의 성능 문제를 해결
Use Hilt in your Android app
Android 의존성 주입을 위한 Jetpack의 권장 라이브러리
• Android 클래스 (Activity, Fragment 등) 에 표준 컨테이너를 제공
• 자동으로 수명주기를 관리하여 DI 를 적용
• 2021년 4월 부터 stable 버전 릴리즈 (현재 2.38.1ver)
Use Hilt in your Android app
Dagger의 bene
fi
t을 그대로 가지면서 +
𝜶
• compile-time correctness
• runtime performance
• scalability
• Android Studio support that Dagger provides
• + Boilerplate Code 감소 (개발자가 작성해야 하는 코드 감소)
• + Jetpack Library 지원 (별도 컨테이너 구현 필요 X)
• + Dagger2 의 러닝커브에 비해 쉬운 사용성
Dagger-Hilt
지원하는 Android Class + Jetpack Libraries
• Application (by using @HiltAndroidApp)
• Activity
• Fragment
• View
• Service
• BroadcastReceiver
ViewModel (by using @HiltViewModel)
Navigation
Compose
WorkManager
Dagger-Hilt 적용 해보기
Application
class MyApplication : Application(), HasAndroidInjector {
@Inject
lateinit var androidInjector: DispatchingAndroidInjector<Any>
override fun androidInjector(): AndroidInjector<Any> {
return androidInjector
}
override fun onCreate() {
super.onCreate()
DaggerAppComponent.factory()
.create(this)
.inject(this)
}
}
Dagger
@HiltAndroidApp
class MyApplication : Application() { /* … */ }
Hilt
Dagger-Hilt 적용 해보기
Activity, Fragment (Module 사용)
class MyActivity : AppCompatActivity(), HasAndroidInjector {
@field:Inject
lateinit var androidInjector: DispatchingAndroidInjector<Any>
protected set
override fun androidInjector(): AndroidInjector<Any> {
return androidInjector
}
Dagger
@Singleton
@Component(
modules = [
AndroidSupportInjectionModule::class,
AppModule::class,
ActivityModule::class
]
)
abstract class AppComponent : AndroidInjector<MyApplication> {
@Component.Factory
abstract class Factory : AndroidInjector.Factory<MyApplication>
}
@Module
interface ActivityModule {
@ActivityScope @ContributesAndroidInjector(modules = [MyModule::class])
fun myActivity(): MyActivity
@Module
abstract class MyModule {
@Binds
abstract fun bindFragmentActivity(activity: MyActivity): FragmentActivity
컴포넌트 정의
(안드로이드 지원 모듈, Activity, App 모듈)
Activity Scope 를 가지는 모듈
해당 Activity 모듈에 bind 및 provide 할 종속성 정의
HasAndroidInjector 를 반드시 구현, 및 @Inject 로 주입 받기
Dagger-Hilt 적용 해보기
Component scopes
Dagger-Hilt 적용 해보기
Activity, Fragment (Module 사용)
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {
@Inject
lateinit var analytics: AnalyticsService
...
}
// If AnalyticsService is an interface.
@Module
@InstallIn(SingletonComponent::class)
abstract class AnalyticsModule {
@Singleton
@Binds
abstract fun bindAnalyticsService(
analyticsServiceImpl: AnalyticsServiceImpl
): AnalyticsService
}
@Inject 로 주입 받기
Hilt
Module 이 Bind 할 Hilt 컴포넌트 지정
@Bind 로 주입
// If you don't own AnalyticsService.
@Module
@InstallIn(SingletonComponent::class)
object AnalyticsModule {
@Singleton
@Provides
fun provideAnalyticsService(): AnalyticsService {
return Retrofit.Builder()
.baseUrl("https://example.com")
.build()
.create(AnalyticsService::class.java)
}
}
@Provides 로 의존성 제공
object
Fragment 도 동일
Dagger-Hilt 적용 해보기
Jetpack ViewModel
public class DaggerAwareViewModelFactory
@Inject public constructor(
private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards
Provider<ViewModel>>
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
var creator = creators[modelClass]
if (creator == null) {
for ((key, value) in creators) {
if (modelClass.isAssignableFrom(key)) {
creator = value
break
}
}
}
if (creator == null) {
error("unknown model class $modelClass")
}
try {
return creator.get() as T
} catch (e: Exception) {
throw e
}
}
}
@MapKey
public annotation class ViewModelKey(val value: KClass<out ViewModel>)
Dagger
abstract class MyModule {
@Binds
fun provideViewModelFactory(factory: DaggerAwareViewModelFactory): ViewModelProvider.Factory
@Binds
@IntoMap
@ViewModelKey(MyViewModel::class)
abstract fun bindMyViewModel(viewModel: MyViewModel): ViewModel
@Binds
abstract fun bindFragmentActivity(activity: MyActivity): FragmentActivity
…
@Module
companion object {
@JvmStatic
@ViewModelInject
@Provides
fun provideMyViewModel(
activity: MyActivity,
viewModelFactory: ViewModelProvider.Factory
): MyViewModel = ViewModelProvider(activity, viewModelFactory).get()
Map Key 를 사용하는 ViewModelFactory 정의
ViewModelFactory 를 통해 ViewModel 주입
@field:ViewModelInject
@field:Inject
public lateinit var viewModel: VM
protected set
Map 을 사용한 멀티 바인딩
Activity or Fragment 에서 Inject 하여 사용
여전히 매번 모듈 작성에 대한 Boilerplate Code 발생
Dagger-Hilt 적용 해보기
Jetpack ViewModel
@AndroidEntryPoint
class MyActivity : AppCompatActivity() {
val viewModel: MyViewModel by viewModels()
@HiltViewModel
class MyViewModel @Inject constructor(
MyRepository: MyRepository
) : ViewModel()
Hilt
by using @HiltViewModel
by viewModels() KTX 확장을 사용하여 주입 가능
모듈 작성 시 발생하는 Boilerplate Code 없음
Jetpack 라이브러리를 지원, 직관적인 사용 가능
Migrating to Hilt
스마일페이 -> G마켓, 옥션 ?
• Dagger and Hilt code can coexist in the same codebase.
• However, in most cases it is best to use Hilt to manage all of your usage of
Dagger on Android.
Reference
• https://developer.android.com/training/dependency-injection
• https://developer.android.com/training/dependency-injection/hilt-android
• https://developer.android.com/training/dependency-injection/hilt-jetpack
• https://velog.io/@wlsdud2194/what-is-di
• https://tecoble.techcourse.co.kr/post/2020-09-19-what-is-test-double/
• https://velog.io/@ptm0304/ViewModel%EC%97%90-
%EC%9D%98%EC%A1%B4%EC%84%B1-
%EC%A3%BC%EC%9E%85%ED%95%98%EA%B8%B0-Dagger-2-Java
• http://labs.brandi.co.kr/2021/04/27/kimdy3.html
감사합니다

More Related Content

Similar to Android DI With Hilt

HolubOnPatterns/chapter2_2
HolubOnPatterns/chapter2_2HolubOnPatterns/chapter2_2
HolubOnPatterns/chapter2_2
SeungHyun Hwang
 
[1A5]효율적인안드로이드앱개발
[1A5]효율적인안드로이드앱개발[1A5]효율적인안드로이드앱개발
[1A5]효율적인안드로이드앱개발
NAVER D2
 
V8 add on with middleware modules
V8 add on with middleware modulesV8 add on with middleware modules
V8 add on with middleware modules
Jay Kim
 
[2022]Flutter_IO_Extended_Korea_멀티모듈을활용한플러터클린아키텍처_...
[2022]Flutter_IO_Extended_Korea_멀티모듈을활용한플러터클린아키텍처_...[2022]Flutter_IO_Extended_Korea_멀티모듈을활용한플러터클린아키텍처_...
[2022]Flutter_IO_Extended_Korea_멀티모듈을활용한플러터클린아키텍처_...
Taekyu Lim
 

Similar to Android DI With Hilt (20)

Angular2를 활용한 컴포넌트 중심의 개발
Angular2를 활용한 컴포넌트 중심의 개발Angular2를 활용한 컴포넌트 중심의 개발
Angular2를 활용한 컴포넌트 중심의 개발
 
HolubOnPatterns/chapter2_2
HolubOnPatterns/chapter2_2HolubOnPatterns/chapter2_2
HolubOnPatterns/chapter2_2
 
반복적인 작업이 싫은 안드로이드 개발자에게
반복적인 작업이 싫은 안드로이드 개발자에게반복적인 작업이 싫은 안드로이드 개발자에게
반복적인 작업이 싫은 안드로이드 개발자에게
 
[1A5]효율적인안드로이드앱개발
[1A5]효율적인안드로이드앱개발[1A5]효율적인안드로이드앱개발
[1A5]효율적인안드로이드앱개발
 
Spring boot 공작소(1-4장)
Spring boot 공작소(1-4장)Spring boot 공작소(1-4장)
Spring boot 공작소(1-4장)
 
Atlassian JIRA Plugin 및 REST API를 이용한 기능 확장
Atlassian JIRA Plugin 및 REST API를 이용한 기능 확장Atlassian JIRA Plugin 및 REST API를 이용한 기능 확장
Atlassian JIRA Plugin 및 REST API를 이용한 기능 확장
 
Front end dev 2016 & beyond
Front end dev 2016 & beyondFront end dev 2016 & beyond
Front end dev 2016 & beyond
 
다시보는 Angular js
다시보는 Angular js다시보는 Angular js
다시보는 Angular js
 
안드로이드를 위한 Gradle 맛들이기
안드로이드를 위한 Gradle 맛들이기안드로이드를 위한 Gradle 맛들이기
안드로이드를 위한 Gradle 맛들이기
 
4-3. jquery
4-3. jquery4-3. jquery
4-3. jquery
 
Policy based Class Design
Policy based Class DesignPolicy based Class Design
Policy based Class Design
 
Spring boot 5장 cli
Spring boot 5장 cliSpring boot 5장 cli
Spring boot 5장 cli
 
V8 add on with middleware modules
V8 add on with middleware modulesV8 add on with middleware modules
V8 add on with middleware modules
 
[2022]Flutter_IO_Extended_Korea_멀티모듈을활용한플러터클린아키텍처_...
[2022]Flutter_IO_Extended_Korea_멀티모듈을활용한플러터클린아키텍처_...[2022]Flutter_IO_Extended_Korea_멀티모듈을활용한플러터클린아키텍처_...
[2022]Flutter_IO_Extended_Korea_멀티모듈을활용한플러터클린아키텍처_...
 
Design patterns
Design patternsDesign patterns
Design patterns
 
Cygnus unit test
Cygnus unit testCygnus unit test
Cygnus unit test
 
Angular 2 rc5 조사
Angular 2 rc5 조사Angular 2 rc5 조사
Angular 2 rc5 조사
 
Dagger with multi modules
Dagger with multi modulesDagger with multi modules
Dagger with multi modules
 
[Codelab 2017] ReactJS 기초
[Codelab 2017] ReactJS 기초[Codelab 2017] ReactJS 기초
[Codelab 2017] ReactJS 기초
 
Hacosa jquery 1th
Hacosa jquery 1thHacosa jquery 1th
Hacosa jquery 1th
 

Android DI With Hilt

  • 1. 발표자 : 이상수(vviprogrammer@gmail.com) (2022-06) DI(Dependency Injection) With Dagger-Hilt
  • 2. DI 란? DI = Dependency Injection = 의존성(종속성) 주입 • 한 클래스가 다른 클래스에 대한 참조가 필요할 때 • Ex) Car 클래스에서 Engine 클래스에 대한 참조가 필수 일때, 의존성을 가지게 된다 class Engine() {} class Car { private val engine = Engine() // 의존성 }
  • 3. DI 란? 클래스가 필요한 의존성(인스턴스)을 얻는 세 가지 방법 1. 필요한 클래스 인스턴스 직접 생성 및 초기화 2. 다른 곳으로 부터 끌어오기 (Ex. Context 게터, getSystemService() 등) 3. 파라미터로 제공 받기 (생성자나 함수 등 에서 필요한 의존성을 전달 받기)
  • 4. DI 란? DI(의존성 주입) 을 하지 않는 코드 class Car { private val engine = Engine() fun start() { engine.start() } } fun main(args: Array) { val car = Car() car.start() } • Car와 Engine은 강하게 커플링 됨 • 테스트가 어려움 (*Test Double 등) * Test Double : 테스트를 진행하기 어려운 경우 이를 대신해 테스트를 진행할 수 있도록 만들어주는 객체를 말한다.
  • 5. DI 란? DI(의존성 주입) 을 사용한 코드 class Car(private val engine: Engine) { fun start() { engine.start() } } fun main(args: Array) { val engine = Engine() val car = Car(engine) car.start() } • 재사용성 ⬆ (Car 클래스) • Ex) ElectricEngine • 테스트 쉬움 • Ex) FakeEngine
  • 6. DI 란? Android 에서 주로 사용하는 2가지 DI 방법 1. 생성자 주입(Constructor Injection) 2. 필드 주입(Field Injection)(or Setter Injection) class Car { lateinit var engine: Engine fun start() { engine.start() } } fun main(args: Array) { val car = Car() car.engine = Engine() // 필드 주입 car.start() }
  • 7. Automated dependency injection 수동 의존성 주입의 문제점 • 큰 프로젝트에서 올바른 DI 를 해주기 위해서는 많은 양의 boilerplate code 필요 • 앱의 수명 주기를 관리하는 지정 컨테이너를 직접 작성해야하고 유지해야함
  • 8. Automated dependency injection 의존성 주입 라이브러리 • 의존성 생성과 제공 프로세스를 자동화 하는 라이브러리 • 런타임에 의존성을 주입하는 리플렉션 기반 솔루션 • 컴파일 타임에 의존성을 연결하는 코드를 생성하는 정적 솔루션 • Google 의 Dagger • Java, Kotlin 및 Android 용 DI로 널리 사용 • 완전 정적 컴파일 타임 DI로 리플렉션 기반 솔루션(Guice 등)의 성능 문제를 해결
  • 9. Use Hilt in your Android app Android 의존성 주입을 위한 Jetpack의 권장 라이브러리 • Android 클래스 (Activity, Fragment 등) 에 표준 컨테이너를 제공 • 자동으로 수명주기를 관리하여 DI 를 적용 • 2021년 4월 부터 stable 버전 릴리즈 (현재 2.38.1ver)
  • 10. Use Hilt in your Android app Dagger의 bene fi t을 그대로 가지면서 + 𝜶 • compile-time correctness • runtime performance • scalability • Android Studio support that Dagger provides • + Boilerplate Code 감소 (개발자가 작성해야 하는 코드 감소) • + Jetpack Library 지원 (별도 컨테이너 구현 필요 X) • + Dagger2 의 러닝커브에 비해 쉬운 사용성
  • 11. Dagger-Hilt 지원하는 Android Class + Jetpack Libraries • Application (by using @HiltAndroidApp) • Activity • Fragment • View • Service • BroadcastReceiver ViewModel (by using @HiltViewModel) Navigation Compose WorkManager
  • 12. Dagger-Hilt 적용 해보기 Application class MyApplication : Application(), HasAndroidInjector { @Inject lateinit var androidInjector: DispatchingAndroidInjector<Any> override fun androidInjector(): AndroidInjector<Any> { return androidInjector } override fun onCreate() { super.onCreate() DaggerAppComponent.factory() .create(this) .inject(this) } } Dagger @HiltAndroidApp class MyApplication : Application() { /* … */ } Hilt
  • 13. Dagger-Hilt 적용 해보기 Activity, Fragment (Module 사용) class MyActivity : AppCompatActivity(), HasAndroidInjector { @field:Inject lateinit var androidInjector: DispatchingAndroidInjector<Any> protected set override fun androidInjector(): AndroidInjector<Any> { return androidInjector } Dagger @Singleton @Component( modules = [ AndroidSupportInjectionModule::class, AppModule::class, ActivityModule::class ] ) abstract class AppComponent : AndroidInjector<MyApplication> { @Component.Factory abstract class Factory : AndroidInjector.Factory<MyApplication> } @Module interface ActivityModule { @ActivityScope @ContributesAndroidInjector(modules = [MyModule::class]) fun myActivity(): MyActivity @Module abstract class MyModule { @Binds abstract fun bindFragmentActivity(activity: MyActivity): FragmentActivity 컴포넌트 정의 (안드로이드 지원 모듈, Activity, App 모듈) Activity Scope 를 가지는 모듈 해당 Activity 모듈에 bind 및 provide 할 종속성 정의 HasAndroidInjector 를 반드시 구현, 및 @Inject 로 주입 받기
  • 15. Dagger-Hilt 적용 해보기 Activity, Fragment (Module 사용) @AndroidEntryPoint class ExampleActivity : AppCompatActivity() { @Inject lateinit var analytics: AnalyticsService ... } // If AnalyticsService is an interface. @Module @InstallIn(SingletonComponent::class) abstract class AnalyticsModule { @Singleton @Binds abstract fun bindAnalyticsService( analyticsServiceImpl: AnalyticsServiceImpl ): AnalyticsService } @Inject 로 주입 받기 Hilt Module 이 Bind 할 Hilt 컴포넌트 지정 @Bind 로 주입 // If you don't own AnalyticsService. @Module @InstallIn(SingletonComponent::class) object AnalyticsModule { @Singleton @Provides fun provideAnalyticsService(): AnalyticsService { return Retrofit.Builder() .baseUrl("https://example.com") .build() .create(AnalyticsService::class.java) } } @Provides 로 의존성 제공 object Fragment 도 동일
  • 16. Dagger-Hilt 적용 해보기 Jetpack ViewModel public class DaggerAwareViewModelFactory @Inject public constructor( private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>> ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun <T : ViewModel?> create(modelClass: Class<T>): T { var creator = creators[modelClass] if (creator == null) { for ((key, value) in creators) { if (modelClass.isAssignableFrom(key)) { creator = value break } } } if (creator == null) { error("unknown model class $modelClass") } try { return creator.get() as T } catch (e: Exception) { throw e } } } @MapKey public annotation class ViewModelKey(val value: KClass<out ViewModel>) Dagger abstract class MyModule { @Binds fun provideViewModelFactory(factory: DaggerAwareViewModelFactory): ViewModelProvider.Factory @Binds @IntoMap @ViewModelKey(MyViewModel::class) abstract fun bindMyViewModel(viewModel: MyViewModel): ViewModel @Binds abstract fun bindFragmentActivity(activity: MyActivity): FragmentActivity … @Module companion object { @JvmStatic @ViewModelInject @Provides fun provideMyViewModel( activity: MyActivity, viewModelFactory: ViewModelProvider.Factory ): MyViewModel = ViewModelProvider(activity, viewModelFactory).get() Map Key 를 사용하는 ViewModelFactory 정의 ViewModelFactory 를 통해 ViewModel 주입 @field:ViewModelInject @field:Inject public lateinit var viewModel: VM protected set Map 을 사용한 멀티 바인딩 Activity or Fragment 에서 Inject 하여 사용 여전히 매번 모듈 작성에 대한 Boilerplate Code 발생
  • 17. Dagger-Hilt 적용 해보기 Jetpack ViewModel @AndroidEntryPoint class MyActivity : AppCompatActivity() { val viewModel: MyViewModel by viewModels() @HiltViewModel class MyViewModel @Inject constructor( MyRepository: MyRepository ) : ViewModel() Hilt by using @HiltViewModel by viewModels() KTX 확장을 사용하여 주입 가능 모듈 작성 시 발생하는 Boilerplate Code 없음 Jetpack 라이브러리를 지원, 직관적인 사용 가능
  • 18. Migrating to Hilt 스마일페이 -> G마켓, 옥션 ? • Dagger and Hilt code can coexist in the same codebase. • However, in most cases it is best to use Hilt to manage all of your usage of Dagger on Android.
  • 19. Reference • https://developer.android.com/training/dependency-injection • https://developer.android.com/training/dependency-injection/hilt-android • https://developer.android.com/training/dependency-injection/hilt-jetpack • https://velog.io/@wlsdud2194/what-is-di • https://tecoble.techcourse.co.kr/post/2020-09-19-what-is-test-double/ • https://velog.io/@ptm0304/ViewModel%EC%97%90- %EC%9D%98%EC%A1%B4%EC%84%B1- %EC%A3%BC%EC%9E%85%ED%95%98%EA%B8%B0-Dagger-2-Java • http://labs.brandi.co.kr/2021/04/27/kimdy3.html