Dagger2 는 무엇인가?
Dagger2 탐구와 적용기 작성
DI (Dependency Injection)?
Dependency = 의존성, Injection = 주입
##DI를 사용 하는 이유는?
테스트
- 모듈을 Testable 하게 만들 수 있음. 독립된 모듈에 대한 테스트 코드 작성 유용함
유지보수
- 하나의 모듈이 변경 되어도 다른 모듈들이 영향을 받지 않아서, 유지보수 용이함
재사용성
- 객체 색성을 외부에서 하면 클래스 독립성이 증가되며, 재사용 가능성이 높아짐
Dagger?
DI Framework.
@Inject
- 주입 받는자, 의존성 주입을 요청
- 의존성 주입을 통해서 해당 어노테이션이 달린 클래스나 필드에게 값을 주입해 달라고 요청
@Component
- 연결자, 의존성을 주입하는 역할 (Inject —(Component) — Module)
- 연결된 Module을 이용하여 의존성 객체를 생성하고 Inject 로 요청받은 인스턴스에 객체 주입
@Module
- 공급자, Component 에 연결되어 의존성 객체 생성. 생성 후 Scope 따라 관리도 가능
@Scope
- 생성된 객체의 Lifecycle 범위
- PerActivity, PerFragment 등으로 화면의 생명주기와 맞추어 사용
Dagger 적용하기
build.gradle
apply plugin: 'kotlin-kapt'
dependencies {
implementation 'com.google.dagger:dagger-android:2.21'
implementation 'com.google.dagger:dagger-android-support:2.21'
kapt 'com.google.dagger:dagger-android-processor:2.21'
kapt 'com.google.dagger:dagger-compiler:2.21'
}
Application Component
AppComponent.kt
@Component(
// 연결할 모듈을 정의
modules = [
AndroidSupportInjectionModule::class,
AppModule::class,
NetworkModule::class,
ActivityBuilder::class]
)
@Singleton
interface AppComponent : AndroidInjector<AppApplication>{
// Application 연결을 도와줄 Builder 정의
@Component.Builder
abstract class Builder : AndroidInjector.Builder<AppApplication>()
}
어플리케이션 수명 = 컴포넌트 수명
@Component 를 붙이면 어노테이션 프로세서에 이해 자동으로 생성되는 클래스 명이 DaggerAppComponent 가 됨
Application
AppApplication.kt
class AppApplication : DaggerApplication() {
// AppComponent 에서 정의한 Builder 로 Component 와 연결
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
return DaggerAppComponent.builder().create(this)
}
}
DaggerApplication 로 만든 후, 이전에 만든 컴포넌트를 이용하여 안드로이드 인젝터 생성
Application Module
AppModule.kt
@Module
class AppModule {
// DataRepository 타입 의존성 객체 생성
@Provides
@Singleton
internal fun provideRepository(apiService: ApiService): DataRepository = DataRepository(apiService)
}
어플리케이션 생명주기 동안, 살아있는 객체들을 제공함 (@Provides 달린 메서드에 @Singleton 스코프 사용하는 이유)
Activity Module
ActivityBuilder.kt
@Module
abstract class ActivityBuilder {
// ContributesAndroidInjector 어노테이션을 달고, 반환타입을 통해 해당 Activity Subcomponent 생성
// SubComponent 와 연결할 modules 정의, Module 들이 실제 의존성 객체를 생성
@ActivityScope
@ContributesAndroidInjector(modules = [ProfileActivityModule::class])
abstract fun bindMainActivity(): ProfileActivity
}
@PerActivity
- 액티비티 생명주기에 맞추어 객체 관리 (어노테이션이 달려있는 클래스는 액티비티가 살아있는 동안 존재)
@ContirubutesAndroidInjector
- 반환하는 객체가 생성되는 시점에 injection을 제공할 모듈을 명시
###Scope
PerActivity.kt
@Scope
@Retention(AnnotationRetention.RUNTIME)
annotation class PerActivity
PerFragment.kt
@Scope
@Retention(AnnotationRetention.RUNTIME)
annotation class PerFragment
객체의 수명이 Activity orFragment 의 수명을 따를 경우 사용하는 사용자 정의 스코프 어노테이션.
ProfileActivity.kt
// DaggerAppCompatActivity 상속받아 Component 연결
class ProfileActivity : DaggerAppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
supportFragmentManager.beginTransaction()
.replace(R.id.container, ProfileFragment())
.commitNow()
}
}
ProfileFragment.kt
// DaggerFragment 상속받아 Component 연결
class ProfileFragment : DaggerFragment() {
// DataRepository 타입 의존성 주입 요청
@Inject
lateinit var repository: DataRepository
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_main, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
....
}
}
소스코드
android-dagger-example - github Dagger2 sample app
참고 하면 좋은글
Written on April 4, 2019