Nuke Olaf - Log Store
[Android] 안드로이드 - Koin (코틀린 개발자를 위한 경량화된 DI 프레임워크) 사용법 본문
1. Koin 이란?
Koin 이란, 순수 kotlin 으로 작성된 Dependency Injection 프레임워크 (이하 DI 프레임워크)이다.
DI 란 Inverse Of Control (제어 역전) 을 통해 객체끼리의 의존 관계를 분리시키는 디자인 패턴을 말한다.
즉, 쉽게 말해서 객체 A 내부에서 객체 B 를 어떤 방식으로든 사용하는 경우 객체 B 에 대해 객체 A 가 의존하고 있다고 볼수 있으며, 객체 A 에서 객체 B 를 초기화 하지 않고 사용할 수 있도록 외부에서 객체 B 를 초기화하여 객체 A 에 주입해주는 것을 DI 라고 생각할 수 있다.
DI 관련 내용 정리 포스팅 : https://salix97.tistory.com/264
안드로이드에서 대표적으로 많이 사용하는 DI 프레임워크로 Dagger 가 있지만, Koin 에 비해 상대적으로 코드를 더 많이 생성하며, 러닝커브가 높다.
2. Koin 사용법 (with MVVM)
MVVM 패턴에서의 Model 레이어에 Koin 을 적용하는 과정을 예로 들어 작성했다.
(1) Koin 의 버전을 확인하고 Module: app 수준의 build.gradle 에 필요한 dependency 를 추가해준다.
2020.6.6 기준 current version : 2.1.5
// Koin AndroidX Scope feature
implementation "org.koin:koin-androidx-scope:2.1.5"
// Koin AndroidX ViewModel feature
implementation "org.koin:koin-androidx-viewmodel:2.1.5"
// Koin AndroidX Fragment Factory (unstable version)
implementation "org.koin:koin-androidx-fragment:2.1.5"
(2) DI 를 사용할 DataSource 와 Repository, ViewModle 은 다음과 같이 작성했다.
interface LocalDataSource {}
class LocalDataSourceImpl(context: Context) : LocalDataSource {}
interface RemoteDataSource {}
class RemoteDataSourceImpl(api: RetrofitApi): RemoteDataSource {}
interface Repository {}
class RepositoryImpl(
private val localDataSource: LocalDataSource,
private val RemoteDataSource: RemoteDataSource
) {}
class MyViewModel(
private val Repository: Repository
) : ViewModel() {}
(3) module 함수를 이용하여 다음과 같이 모듈을 생성했다.
// Model 레이어에 대한 모듈
val appModule = module {
single<LocalDataSource> { LocalDataSourceImpl(androidContext) }
single<RemoteDataSource> { RemoteDataSourceImpl(get()) }
single<Repository> { RepositoryImpl(get(), get()) }
}
// 레트로핏 객체에 대한 모듈
val retrofitModule = module {
single {
OkHttpClient.Builder()
.addInterceptor(get<Interceptor>())
.addInterceptor(get<HttpLoggingInterceptor>())
.build()
}
single {
Interceptor { chain: Interceptor.Chain ->
val original = chain.request()
chain.proceed(original.newBuilder().apply {
addHeader("Authorizaion_Header", "access_token")
}.build())
}
}
single {
HttpLoggingInterceptor().apply {
level = if (BuildConfig.DEBUG) {
HttpLoggingInterceptor.Level.BODY
} else {
HttpLoggingInterceptor.Level.NONE
}
}
}
single {
Retrofit.Builder()
.baseUrl(BASE_URL)
.client(get())
.addConverterFactory(GsonConverterFactory.create())
.build()
}
single {
get<Retrofit>().create(
RetrofitInterface::class.java
)
}
}
// ViewModel 에 대한 모듈
val viewModelModule = module {
viewModel { MyViewModel(get()) }
}
* Koin 에서 사용할 수 있는 DSL (Domain Specific Langauge) 은 다음과 같다
A quick recap of the Koin DSL keywords:
- module { } - create a Koin Module or a submodule (inside a module)
- factory { } - inject 할 때마다 인스턴스 생성
- single { } - 싱글톤으로 생성
- get() - resolve a component dependency
- named() - define a qualifier with type, enum or string
- bind - additional Kotlin type binding for given bean definition
- binds - list of additional Kotlin types binding for given bean definition
- getProperty() - resolve a Koin property
(4) 이제 application class 에서 startKoin() 함수를 호출하여 위에서 선언한 module 들을 시작시킨다.
참고로, Application 을 Manifest 에 등록해야 동작한다.
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
androidContext(this@MovieApp)
modules(
appModule,
retrofitModule,
viewModelModule
)
}
}
}
<application
android:name=".MyApplication" // Manifest 에 Application 등록
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
(5) Activity Class 에서 "by inject()" delegate injector 를 사용하여 필요한 객체를 주입한다.
by inject() 함수는 Android 컴포넌트의 runtime 에서만 Koin 인스턴스를 사용할 수 있게 한다 (Activity, Fragment, Service...)
class MainActivity : AppCompatActivity() {
private val viewModel: MyViewModel by inject()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
}
참고 링크 >>>
koin 공식 문서 : https://start.insert-koin.io/#/
https://blog.yudiz.com/what-is-koin-kotlin-dependency-injection/
https://jungwoon.github.io/android/2019/08/21/Koin/
https://medium.com/@velmm/koin-dependency-injection-framework-for-android-aa34c0737956
'Android' 카테고리의 다른 글
[Android] 안드로이드 리사이클러뷰에서 Flexbox 사용하기 (FlexboxLayoutManager) feat. 스크롤 없는 태그 입력 리사이클러뷰 (0) | 2020.06.30 |
---|---|
[Android] 안드로이드 - 액티비티 화면전환 애니메이션과 플래그 (액티비티만으로 탭바 레이아웃 만들기) (0) | 2020.06.30 |
[Android] 안드로이드 - DI (Dependency Injection) (0) | 2020.06.01 |
[Android] 안드로이드 - DataBinding 에서 String Format 적용 (0) | 2020.05.31 |
[Android] 안드로이드 - AAC View Model 과 Live data (0) | 2020.05.26 |