이 글을 이해하기 위해서는 의존성 주입에 대한 이해가 필수적이다. 의존성주입에 관해 모른다면 아래 글을 읽고 오도록 하자.
Koin과 의존성 주입의 구성요소
의존성 주입에는 주입할 객체를 저장하는 Container, 주입할 객체가 필요하다. Koin에서는 여기에 하나를 더해 주입할 객체를 모아놓은 모듈을 만들어내었다.
따라서 Network를 위한 객체들은 Network Module에 모아지고, Database를 위한 객체들을 Database Module에 모아진다. 다음으로 Network Module과 Database Module을 Container에 들어간다.
이러한 Container에 들어있는 5개 객체(BaseUrl, OkHttpClient, Retrofit, AppDatabase, Dao)는 주입되어야 하는 곳에 주입되게 된다. 각 모듈들은 이러한 Object들을 묶어주는 역할만을 하며, 다른 일은 아무것도 하지 않는다.
의존성 주입 IOC Container 만들기
예제 링크 : https://github.com/seyoungcho2/KoinExample
예제 브랜치명 : example/example1 *브랜치 필수 확인
위의 그림1은 너무 복잡하니 그림2의 간단한 예제로 의존성 주입을 시작해보자
코드 구조는 그림3과 같다.
class Student(val name: String)
class Teacher(val name: String)
Container 만들기
먼저 의존성 주입을 위해서는 컨테이너가 필요하다. 또한 안드로이드에서 컨테이너는 안드로이드 컴포넌트의 Lifecycle에 맞추어 생성과 파괴가 되도록 만들어져야 한다. 이러한 부분은 아래 코드와 같이 startKoin 블록 사이에 androidContext 메서드를 넣어 설정할 수 있다.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
/* Container 시작 */
startKoin {
androidContext(this@MainActivity)
}
/* Container 종료 */
}
}
위와 같이 this@MainActivity가 들어갈 경우 이 Container은 MainActivity가 파괴될 때 파괴된다.
주입할 모듈 만들기
다음은 컨테이너 안에 들어갈 모듈을 만들어야 한다. 아래 코드와 같이 만들 수 있다.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
startKoin {
androidContext(this@MainActivity)
modules(
/* Module 시작 */
module {
}
/* Module 종료 */
)
}
}
}
이제 모듈이 여러개라면 modules 내부를 다음과 같이 바꾸면 된다.
modules(
/* Module1 시작 */
module {
}
/* Module1 종료 */
,
/* Module2 시작 */
module {
}
/* Module2 종료 */
)
주입할 객체 만들기
주입할 객체를 만드는 방법은 두가지이다. 하나는 single 방식이고 하나는 factory 방식이다. single은 singleton의 약자로 Container 내부에서 객체가 한 번만 생성되며, factory는 Container 내부에서 객체가 불릴 때마다 새로 생성된다.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
startKoin {
androidContext(this@MainActivity)
modules(
module {
/* 하나만 생성되고 재활용되는 Singleton Object 만들기 */
single { Teacher("teacher-cho") }
/* 매번 새로 생성되는 Factory Object 만들기 */
factory { Student("student-kim") }
}
)
}
}
}
의존성 주입하기
by inject()라는 위임 메서드를 통해 주입이 가능하다.
val student : Student by inject()
자 이제 MainActivity에서 주입 두개의 객체를 사용해 textview에 세팅해보자.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
..
val teacher : Teacher by inject()
val student : Student by inject()
findViewById<TextView>(R.id.textViewTeacher).text = teacher.name
findViewById<TextView>(R.id.textViewStudent).text = student.name
}
}
결과는 다음과 같이 나온다.
이번 글을 통해 Koin 의존성 주입이 되는지 흐름을 이해했다.
다음 글부터는 의존성 주입을 하는 방법을 더욱 깊숙히 다룰 것이다.