2022년 9월 16일 금요일

Kotlin Koin

Kotlin Koin

Kotiln Koin

Koin은 Kotlin 개발자를 위한 실용적인 경량 종속성 주입 프레임워크로 순수한 Kotlin 언어로 작성되었으며 함수 파싱만 사용하고 프록시, 코드 생성 및 리플렉션이 없습니다.

코인이 리플렉션을 사용할 필요가 없는 이유는?

Koin은 kotlin을 기반으로 개발되었기 때문에 kotlin의 강력한 구문(예: Inline, Reified 등)과 함수형 프로그래밍을 사용하여 간단한 예제를 살펴보겠습니다.

Koin설정법은 여기를 참고하세요.

https://yunhos.blogspot.com/2021/05/kotlin-koin.html

설정 3.1.2


```plain
dependencies {
    def koin_version = "3.1.2"
    // Koin main features for Android (Scope,ViewModel ...)
    implementation "io.insert-koin:koin-android:$koin_version"
    // Koin Java Compatibility
    implementation "io.insert-koin:koin-android-compat:$koin_version"
    // Koin for Jetpack WorkManager
    implementation "io.insert-koin:koin-androidx-workmanager:$koin_version"
    // Koin for Jetpack Compose
    implementation "io.insert-koin:koin-androidx-compose:$koin_version"
}

1. Application DSL

KoinApplication코인 주입 항목을 구성하기 위해 다음 API를 사용할 수 있습니다.

  1. koinApplication { }: 코인 컨테이너를 생성합니다.
  2. startKoin { }: Koin 컨테이너 를 생성 하고 에 등록합니다 GlobalContext하여 GlobalContext의 API 를 사용할 수 있습니다 .
  3. logger( ): 사용할 로그 모드를 선택할 수 있습니다. Koin은 AndroidLogger , PrintLogger , EmptyLogger 등 3개의 기본 로거를 제공하며 , 모두 추상 클래스 Logger 에서 상속 합니다. 구성되지 않은 경우 기본적으로 EmptyLogger가 사용됩니다. 즉, 인쇄하지 않습니다.
  4. modules( ): 코인 모듈을 구성하고 코인 컨테이너에 주입합니다.
  5. properties(): HashMap을 사용하여 전역 쿼리 수정을 위한 속성을 삽입합니다.
  6. fileProperties( ): 주어진 속성 파일을 사용하여 속성을 주입합니다. 파일은 src/main/resources 디렉토리에 있어야 합니다.
  7. environmentProperties( ): 주입을 통해 시스템 및 환경 속성을 java.lang.System주입 합니다.

2. Module DSL

  1. module { // module content }: 코인 모듈을 생성합니다.
  2. factory { //definition }: 주입된 클래스의 인스턴스를 생성합니다.
  3. single { //definition }: 싱글톤을 생성한다는 점을 제외하고 와 동일한 factory기능 입니다.
  4. get(): 구성 요소 종속성을 해결하여 클래스 인스턴스를 주입합니다.
  5. inject(): get()함수 둘 다 클래스 주입을 제공하지만 inject지연 로딩을 제공합니다.
  6. bind(): 기본 주입 클래스는 하나의 유형에만 대응할 수 있으므로 주입된 클래스에 유형 바인딩을 추가합니다.
  7. binds(): 기능은 위와 bind()동일하고 여러개에 여러 유형의 바인딩을 제공합니다.
  8. scope { // scope group }: 주입된 클래스의 수명 주기를 제어하는 ​​역할을 하는 그룹을 scoped정의합니다 .
  9. scoped { //definition }: 위의 내용 scope과 정의하여 scope의 범위 내에서만 존재함을 나타냅니다.
  10. named(): 동일한 유형의 주입이 두 개 이상 발생하는 경우 이 기능을 사용하여 주입에 이름을 지정한 다음 주입에 이름을 지정하기만 하면 올바른 주사를 얻을 수 있습니다.

3. 사용법

Application클래스의 onCreate에서 startKoin을 불러내서 사용합니다.

 super.onCreate()
        startKoin {
            androidContext(this@MyApplication) //`androidContext()`는 모듈 내에서 Context를 참조하려는 경우 호출합니다.
// startKoinAndroid 컨텍스트 에서 선언된 Android 컨텍스트 androidContext(this@MyApplication)는 실제로는 전역 주입 Context및 Application싱글톤입니다.
            modules(module{
            viewModel {SplashViewModel()}
            })
        }

Koin-android 라이브러리에는 안드로이드용 viewmodel을 이용할수있도록 미리 준비되어있기 때문에 ViewModel을 연결할경우 아래와 같이 간단하게 할수 있습니다.

-일반적인 뷰모델 클래스 작성
class SplashViewModel : ViewModel() {}

-Koin에서 사용하기 위해서 viewModel을 정의추가
modules(module{
 viewModel {SplashViewModel()}
})

-필요한 곳(Activity, Fragment)에서 호출해서 사용
class SplashActivity : FragmentActivity(), KoinComponent {  
    val splashViewModel: SplashViewModel by viewModel()
    

이렇게 module{} 안에 등록하면 앱실행시에 Koin이 필요한 모듈을 찾아서 사용할 준비를 해줍니다.
모듈을 정의할때 single, factory, viewModel등이 있는데 다음과 갔습니다.
선언의예

val myModule = module { 
	//1
	single{ A() } 
	//2
	factory{ B() } 
	//3
	factory{ C(get()) } 
	//4
	single<F> { FImp() } 
	//5
	single { FImp() } bind F::class 
	//6
	single(named:("special")){ A() } 
	//7
	single{ (view:View) -> D(view) } 
	//8
	single(createdAtStart=true){ A() } 
}

  

  • single
    • 전역 범위의 싱글톤 모드(기본적으로 지연 로딩)는 한 번 생성되면 전체 코인 수명 주기 동안 존재합니다.
module {
	// 매개변수 없는 경우
	single { User() }
	// 재정의(override)해서 사용 할경우
	single(override = true) { User() }
	// 동일한 유형이지만 사용할때 이름으로 구분해서 사용할경우
	single(named("a")) { User() } 
	single(named("b")) { User() }
	// 주입시에 인수를 지정하는 방법과, 인수로서 위에 선언된 모듈을 get()으로 넘기는 경우(UseLoginProcess가3번째인자로 User클래스 타입을 요구할경우)
	single { (phone: String, passWord: String) -> UseLoginProcess(phone, passWord, get()) }
}

- 사용할때는 (지연 로딩, 즉 소스내에서 호출할때 로딩)
val user:User by inject()
val user:User by inject(named("a"))
val useLoginProcess:UseLoginProcess by inject { parametersOf("1111","*****") }
바로 로딩
val user:User = get()
val usera:User = get(named("a"))
val loginBean:LoginBean=get {  parametersOf("189****11","*****")   
}
  • factory
    • 현재 범위의 팩토리 모드에서는 팩토리 메소드 소스 코드를 얻을 때마다 새 인스턴스가 생성됩니다.
module {
factory(User()}
// 이하 Single과 동일 
}
- 사용할때는 (지연 로딩, 즉 소스내에서 호출할때 로딩)
val user:User by inject()
// 이하 Single과 동일 
  • viewModel
    • 안드로이드의 viewModel을 쉽게 정의할수 있도록 해줍니다.
module {
viewModel{ TestViewModel() }
// 이하 Single과 동일 
}
- 사용할때는 (지연 로딩, 즉 소스내에서 호출할때 로딩)
private val viewModel: TestViewModel by viewModel()
// 이하 Single과 동일 

4.Bind

bind()함수는 동시에 바인딩하고자 하는 KClass 타입을 전달해야 하며, 동시에 바인딩해야 하는 타입이 여러 개인 경우 List 타입을 전달하는 binds()함수를 사용합니다.

// 클래스 타입을 명시해서 모듈을 추가할경우 
factory<Engine> { GasEngine() } 
// or 
factory { GasEngine as Engine } 
//  `bind()` 를 사용할 경우
factory { GasEngine() } bind Engine::class

- bind 사용예
val module = module { 
factory { GasEngine() } bind Engine::class 
factory { ElectricEngine() } bind Engine::class 
} 
private val gasEngine = get<Engine>() 
private val electricEngine = get<ElectricEngine>()

5. Qualifier

Qualifier한정자 는 구성 및 주입에 사용되며 factory(), single()함수 는 형식 매개변수를 제공했으며, 이는 함수named() 를 통해 얻을 수 있고 원하는 효과를 얻기 위해 전달할 수 있습니다.
named()3가지 사용 방법 지원:

  1. named(): 제네릭 인증
  2. named(String): 문자열로 한정
  3. named(Enum): 열거형으로 한정
val module = module { 
factory(named("gas")) { GasEngine() } bind Engine::class 
factory(named("electric")) { ElectricEngine() } bind Engine::class } 

private var gasEngine = get<Engine>(named("gas")) 
private var electricEngine = get<Engine>(named("electric"))

  

6. Scope

스코프는 수명 주기를 사용하는 주입을 제공합니다.
범위는 인스턴스의 범위이며 범위가 끝나면 인스턴스가 컨테이너에서 제거됩니다.

Scope 를 구성 할 때 scopeId 와 scopeName 을 지정해야 합니다 . (Qualifier 또는 제네릭을 사용할 수 있습니다 . 인젝션을 사용할 때 먼저 범위를 생성합니다.
다음 기능을 사용할 수 있습니다.

  1. createScope(): 범위 생성
  2. getScope: 범위를 가져옵니다. 존재하지 않으면 예외가 보고됩니다.
  3. getOrCreateScope: 범위 가져오기, 존재하지 않으면 생성하여 반환합니다.

0 comments:

댓글 쓰기