요즘 아주 자주 보이는 DI 종속 항목 삽입의 개념을 알고자

간단한 프로젝트를 생성하여 Koin을 이용한 DI를 적용해봤습니다.

(조용히 숨만 쉬고 사는데도 배워야 할 앱 개발 지식은 끝이 없네요.... 🧑‍💻🧑‍💻)

 

 

 

 

 

간단하게 종속 항목 삽입이란

 

"

   클래스에서 다른 클래스의 참조가 필요한 경우

   그 해당 필요한 다른 클래스를 종속 항목이라 하며

   두 클래스 사이의 의존 관계를 소스코드 내부가 아닌

   외부 설정 파일 등을 통해 정의하게 되는 디자인 패턴입니다.

                                                                                                                                             "

 

 

DI 의존성 주입이란  💉💉

 

Android DI(Dependency Injection) 의존성 주입이 뭐지?

🔥🔥 요즘 아주 핫한 키워드 중 하나죠! DI (Dependency Injection) 종속 항목 주입 또는 의존성 주입 프로그래밍에 널리 사용되는 기법이고 Android 개발에 적합하다고 하는데요 via GIPHY DI? Koin? Dagger? Hil

salmonpack.tistory.com

 

 

 

여러 가지 DI Framework 중 

 Koin

Koin에 대하여 알아보겠습니다.

 

 

➕➕➕

Koin관련 추가 게시물

 

[Kotlin] Koin은 DI가 아니다?!

최근에 흥미로운 글 하나를 읽었습니다. 🧑‍💻🧑‍💻🧑‍💻 "Koin은 DI 인가 Service Locator 인가?" Android DI 하면 그다음 항상 따라오는 Dagger, Hilt, Koin 삼 형제가 있죠 여기서 우리가 귀가 아프도

salmonpack.tistory.com

 


🪙  Koin

 

 

 

KoinKotlin으로 작성된

경량화 Dependency Injection(DI) 프레임워크입니다.

 

 

 

Koin - The Kotlin Dependency Injection Framework

The Kotlin Dependency Injection Framework

insert-koin.io

 

 

Koin의 장점으로는

다른 DI 프레임워크인 Dagger 보다 러닝 커브가 낮아

쉽고 빠르게 DI를 적용할 수 있다는 점입니다.

또한 별도의 어노테이션을 사용하지 않기 때문에

컴파일 시간이 단축됩니다.

 

B U T ❗️

하지만 런타임 시 의존 주입하기 때문에

런타임 시 알 수 없는 오류에 빠지기도 합니다.

또한 Koin은 자세히 살펴보면

DI 패턴이 아닌 Service Locator Service를 사용하는

Service Locator에 의존하는 안티 패턴 이라고 합니다.

(Service Locator관련된 내용은 다음에 다시 정리해보겠습니다..)

 

 

 


 

✔️ Koin lib 설치 방법

 

 

 

Koin 3.3 | Koin

Setup Koin for your project

insert-koin.io

 

koin_android_version= "3.3.0"

// Koin main features for Android
implementation "io.insert-koin:koin-android:$koin_android_version"
// Java Compatibility
implementation "io.insert-koin:koin-android-compat:$koin_android_version"
// Jetpack WorkManager
implementation "io.insert-koin:koin-androidx-workmanager:$koin_android_version"
// Navigation Graph
implementation "io.insert-koin:koin-androidx-navigation:$koin_android_version"
// Jetpack Compose
implementation "io.insert-koin:koin-androidx-compose:$koin_android_version"

 

 


 

✔️ Module 선언

 

Koin으로 주입할 모든 컴포넌트들을 Module의 형태로 선언해야 합니다.

Module에서 제공할 의존성들의 구조를 선언합니다.

 

repositoryModule.kt

val repositoryModule = module {
    factory {
        WeatherRepository(get(), get())
    }
}
WeatherRepository.kt

class WeatherRepository(
    private val baseApi: BasicApi,
    private val weatherNowDao: WeatherNowDao
): KoinComponent {

	...
    
}

 

위와 같이 repositoryModule를 선언하여

WeatherRepository의 의존성 구조를 선언해줬습니다.

WeatherRepository에서는 BasicApi, WeatherNowDao와 의존관계이기 때문에

get()을 통하여 의존 주입을 해주는 구조입니다.

 

 

KoinComponent

갑자기 등장한 KoinComponent

Activity 이외의 장소에서 의존 주입(inject)을 하려면

KoinComponent를 반드시 implement로 추가해야 한다.

 

 

 

아직 감이 잘 안 잡히신다고요?

조금 더 쉬운 예시로 확인해보겠습니다.

 

 

class Alcohol {
	fun drunk(): String = "Al..co..hollll"
}

class Beer(alcohol: Alcohol) {
	fun drunk(): String = alcohol.drunk()
}

 

alcoholModule.kt

val myAlcoholModule = module {
   single {
    	Alcohol()
    }
    
    factory {
    	Beer(get())
    }
}

 

Beer는 Alcohol과 의존 관계입니다.

그렇기 때문에 myAlcoholModule을 선언하여

get()을 이용하여 Alcohol 주입을 선언했습니다.

간단하죠?!

 

여기서 Module을 선언할 때

사용되는 키워드들이 있습니다.

single, factory, viewModel

 

 

 


  • single 

     예를 들면 Retrofit 통신 객체처럼 App 전체 주기 동안

     다일 인스턴스로 존재하는 객체를 싱글톤처럼 생성하여

     주입하게 합니다.

 


  • facctory

     single과 반대로 항상 객체를 생성하여 주입합니다.

     요청(inject, get) 할 때마다 새로운 객체를 생성하여 주입.

 


  • viewModel

     viewModel에 대한 Module 선언입니다.

 

class MainViewModel(
    private val weatherRepository: WeatherRepository
): ViewModel() {

  ...
  
 }
val viewModelModule = module {
    viewModel {
    	MainViewModel(get())
    }
}
class MainActivity {
    ...
    private val viewModel: MainViewModel by viewModel()
    
    ...
}

 

위와 같이 viewModel에 의존 주입 선언한 후

viewModel의 주입 방법은 by 키워드와 viewModel() 함수를 통하여 초기화합니다.

 

 


 

✔ Module 등록

 

위에서 선언해둔 모듈들은 등록 과정이 필요합니다.

모듈을 등록하고 Koin을 시작하려면

startKoin()을 호출하여 Koin의 시작을 알리고

생성해둔 모듈들을 등록해줍니다.

 

class BaseApplication: Application() {

    override fun onCreate() {
        super.onCreate()

        // Koin
        startKoin {
            androidLogger(Level.DEBUG)			// Koin Log Level
            androidContext(this@BaseApplication)	// Android Context
            modules(
                apiModule,
                viewModelModule,
                databaseModule,
                repositoryModule,
                activityModule
            )
        }
    }
}

 

  • androidLogger :  Koin의 로그 레벨을 정합니다.
  • androidContext : Koin에서 안드로이드의 Context를 지정합니다.
  • modules / module : 선언한 Module들을 등록합니다.

 

 


 

💉 의존성 주입하기

 

 

class MainActivity {
    ...
    private val viewModel: MainViewModel by viewModel()
    private val repository: WeatherRepository by inject()
    private val beer:Beer by inject()
    
    ...
}

 

by inject() 또는 by viewModel()을 통하여 

선언해둔 Module를 주입하여 사용합니다.

( by viewModel()은 위에 single, factory, viewModel 설명했던

   선언해둔 viewModel Module을 주입할 때 사용합니다. )

 

 

 

 


여기까지 저의 긴 글을 읽어주셔서 감사합니다.

제가 습관적으로 코딩을 하는 그날까지 습관적으로 코딩을 하기 위해 글 작성을 꾸준하게 해보겠습니다.

 

 

 

 

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기