Android 공부/의존성 주입
Koin
posite
2026. 2. 23. 16:35
Koin
- 순수 코틀린으로 작성된 경량 의존성 주입 프레임워크
- DSL을 사용하여 직관적으로 의존성을 관리할 수 있음 -> 의존성 관계 파악이 어려워질 수 있음
- 런타임에 객체를 생성하고 주입함 -> 런타임 오버헤드가 존재하며 의존성 누락 시 앱 실행 중 크래시 발생
- 컴파일 시 코드를 생성하지 않음 -> 컴파일 속도 빠름
- KMP 지원 : 안드로이드뿐만 아니라 iOS, Desktop 등 공통 코드에서도 DI를 구현할 수 있음
- KSP를 활용한 어노테이션 방식도 지원하여, 기존의 DSL 방식에 컴파일 타임 안정성 향상
예시)
DSL 방식 : get()만 쓰면 Koin이 알아서 타입을 추론해 주입함
class ApiService {
fun fetchData() = "Hello from DSL!"
}
class MainRepository(private val api: ApiService) {
fun getData() = api.fetchData()
}
class MainViewModel(private val repo: MainRepository) : ViewModel() {
val data = repo.getData()
}
val appModule = module {
// single: 앱이 살아있는 동안 딱 하나만 생성 (싱글톤)
single { ApiService() }
// get(): Koin이 관리하는 객체 중 해당 타입을 찾아 자동으로 주입함
single { MainRepository(get()) }
// viewModel: 안드로이드 ViewModel 생명주기에 맞춰 생성 및 파괴 관리
viewModel { MainViewModel(get()) }
}
class MyKoinApp : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
androidContext(this@MyKoinApp)
modules(appModule) // 작성한 모듈 등록
}
}
}
class MainActivity : AppCompatActivity() {
// ViewModel 주입
private val mainViewModel: MainViewModel by viewModel()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Toast.makeText(this, mainViewModel.name, Toast.LENGTH_SHORT).show()
}
}
어노테이션 방식
@Single // DSL의 single { ... } 과 동일
class MviRepository {
fun loadStatus() = "MVI State Active"
}
@KoinViewModel // DSL의 viewModel { ... } 과 동일
class MviViewModel(
private val repo: MviRepository // 생성자 주입이 자동으로 일어남
) : ViewModel() {
// MVI 관련 로직 (Intent, State 등)
}
@Module
@ComponentScan("com.example.myapp") // 이 패키지 아래의 모든 @Single, @KoinViewModel 스캔
class MyAnnotatedModule
class MyKoinApp : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
// MyAnnotatedModule().module 은 KSP가 생성해준 확장 프로퍼티
modules(MyAnnotatedModule().module)
}
}
}
class MainActivity : AppCompatActivity() {
private val mainViewModel: MviViewModel by viewModel()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Toast.makeText(this, mainViewModel.name, Toast.LENGTH_SHORT).show()
}
}