Skip to content

Latest commit

Β 

History

History
228 lines (146 loc) Β· 9.25 KB

How-To-Koin.md

File metadata and controls

228 lines (146 loc) Β· 9.25 KB

How to Koin

Koin을 μ–΄λ–»κ²Œ μ“°λŠ”μ§€ μ•Œμ•„λ΄…μ‹œλ‹Ή~~

μž‘μ„±μž: μ΄μ’…ν˜„

Present Time: 2018-11-9 FRI

0. μ‹œμž‘ν•˜κΈ° 전에, μ œμ–΄μ˜ μ—­μ „μ΄λž€?

koin이 무엇인지 μ•Œμ•„λ³΄κΈ° 전에 μ œμ–΄μ˜ 역전이 무엇인지 μ•Œμ•„λ΄…μ‹œλ‹€.

ν”„λ‘œμ νŠΈκ°€ 컀지면 컀질수둝 ν”„λ‘œκ·Έλž¨μ—μ„œ μ œμ–΄ν•΄μ•Όν•  뢀뢄은 λ§Žμ•„μ§€λ©° μ½”λ“œ 관리가 점점 νž˜λ“€μ–΄μ§‘λ‹ˆλ‹€. κ·Έλž˜μ„œ μ œμ–΄μ˜ μ—­μ „μ΄λΌλŠ” 방법을 μ΄μš©ν•˜μ—¬ μ½”λ“œλ₯Ό κ΄€λ¦¬ν•©λ‹ˆλ‹€.

**μ œμ–΄μ˜ μ—­μ „(Inversion of Control)**은 ν”„λ ˆμž„μ›Œν¬μ— 객체 μ‚¬μš© 및 생성 λ“± μ œμ–΄μ˜ κΆŒν•œμ„ λ„˜κΈ°λ©° ν΄λΌμ΄μ–ΈνŠΈκ°€ 신경써야할 것을 μ€„μ΄λŠ” λ°©λ²•μž…λ‹ˆλ‹€.

0-1. μ–΄λ–»κ²Œ κ΅¬ν˜„ν•΄μš”?

μ œμ–΄μ˜ μ—­μ „ ꡬ쑰λ₯Ό κ΅¬ν˜„ν•  λ•Œμ—λŠ” λŒ€ν‘œμ μΈ λ°©λ²•μœΌλ‘œ **μ˜μ‘΄μ„± μ£Όμž…(Dependency Injection)**κ³Ό **μ„œλΉ„μŠ€ λ‘œμΌ€μ΄ν„°(Service Locator)**κ°€ μžˆμŠ΅λ‹ˆλ‹€.

0-1-1. μ˜μ‘΄μ„± μ£Όμž…μ΄λž€?

class Car{
    val tire = Tire()
    val engine = Engine()
}

μœ„μ™€ 같은 μ½”λ“œλŠ” 객체λ₯Ό Car 클래슀 λ‚΄λΆ€μ—μ„œ 의쑴 객체λ₯Ό μƒμ„±ν•˜κ²Œ λ©λ‹ˆλ‹€. ν•˜μ§€λ§Œ tire와 engine을 λ‚΄λΆ€μ—μ„œ μƒμ„±ν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ 이런 방법은 λͺ¨λ“ˆκ°„μ˜ 결합도가 λ†’κ³ , Mock Objectλ₯Ό μ‚¬μš©ν•˜κΈ° νž˜λ“€κΈ° λ•Œλ¬Έμ— ν…ŒμŠ€νŒ…μ„ ν•  λ•Œ μš©μ΄ν•˜μ§€ μ•Šμ„ 수 μžˆμŠ΅λ‹ˆλ‹€.

0-1-2. μƒμ„±μž, setterλ₯Ό μ΄μš©ν•œ μ˜μ‘΄μ„± μ£Όμž…

val car = Car()
car.tire = Tire()
car.engine = Engine()

val car2 = Car(Tire(), Engine())

μœ„μ²˜λŸΌ μ™ΈλΆ€λ‘œλΆ€ν„° 객체λ₯Ό λ°›μ•„μ˜€κ²Œ 되면 결합도가 떨어지고, ν…ŒμŠ€νŒ…μ„ ν•  κ²½μš°μ—λŠ” Mock Objectλ₯Ό μ£Όμž…ν•˜λ©΄ 되기 λ•Œλ¬Έμ— ν…ŒμŠ€νŠΈκ°€ 더 μš©μ΄ν•΄μ§‘λ‹ˆλ‹€.

DI ν”„λ ˆμž„μ›Œν¬λŠ” μœ„μ²˜λŸΌ 객체λ₯Ό μƒμ„±ν•˜κ³  λ„˜κ²¨μ£Όλ©° 객체의 μ œμ–΄λ₯Ό ν”„λ ˆμž„μ›Œν¬μ—μ„œ ν•˜κ²Œ λ˜λŠ”λ°, μ΄λ•Œ IoC κ°œλ…μ„ κ΅¬ν˜„ν•©λ‹ˆλ‹€.

보톡 Spring같은 ν”„λ ˆμž„μ›Œν¬λ₯Ό μ΄μš©ν•˜μ—¬ DIλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

μ•ˆλ“œλ‘œμ΄λ“œλŠ” Dagger2λΌλŠ” ν”„λ ˆμž„μ›Œν¬λ₯Ό μ΄μš©ν•˜μ—¬ DIλ₯Ό κ΅¬ν˜„ν•©λ‹ˆλ‹€.

0-1-2. Service Locatorλž€?

Service Locatorλž€, μ˜μ‘΄μ„±μ΄ ν•„μš” ν•  λ•Œ, μ™ΈλΆ€μ—μ„œ 클래슀λ₯Ό λ°›μ•„μ™€μ„œ μ‚¬μš©ν•˜λŠ” λ°©μ‹μž…λ‹ˆλ‹€.

class Car{
    val car = Locator.resolve<Car>()
}

class Locator{
    // μ΄ν•˜μƒλž΅
}

μœ„μ²˜λŸΌ Locator ν΄λž˜μŠ€μ—μ„œ 객체λ₯Ό 받아와 μ‚¬μš©ν•˜μ—¬λ„ 결합도λ₯Ό λ–¨μ–΄λœ¨λ¦¬κ³  ν…ŒμŠ€νŠΈν•˜κΈ° μš©μ΄ν•œ μ½”λ“œλ₯Ό μž‘μ„±ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λ¬Όλ‘  μ‹€μ œ DI, Service Locator ν”„λ ˆμž„μ›Œν¬λŠ” μœ„ μ½”λ“œλ³΄λ‹€ 훨씬 쒋은 λ°©λ²•μœΌλ‘œ κ΅¬μ„±λ˜μ–΄ μžˆκ² μ§€λ§Œ, μ΄λ²ˆμ—λŠ” 이해λ₯Ό 돕기 μœ„ν•΄ 이런 예제λ₯Ό μ‚¬μš©ν•˜μ˜€μŠ΅λ‹ˆλ‹Ή~~~

0-2. μ‚¬μš© μ‹œ μ–»λŠ” 이점

ν”„λ ˆμž„μ›Œν¬μ—μ„œ 객체λ₯Ό κ΄€λ¦¬ν•˜κ²Œ 되며 μ—¬λŸ¬κ°€μ§€ 이점을 μ–»κ²Œ λ©λ‹ˆλ‹€.

  1. λ‹€λ₯Έ μ‹œμŠ€ν…œμ΄ 무엇을 할지 좔츑을 ν•˜μ§€ μ•Šμ•„λ„ λ©λ‹ˆλ‹€.
  2. μ‹œμŠ€ν…œμ„ 바꿔도 λ‹€λ₯Έ μ‹œμŠ€ν…œμ— 지μž₯을 주지 μ•ŠμŠ΅λ‹ˆλ‹€.

0-2. 그런데

λ§ˆν‹΄ νŒŒμšΈλŸ¬κ°€ μ“΄ Inversion of Control Containers and the Dependency Injection patternμ΄λΌλŠ” 글을 읽어보면,

As a result I think we need a more specific name for this pattern. Inversion of Control is too generic a term, and thus people find it confusing. As a result with a lot of discussion with various IoC advocates we settled on the name Dependency Injection.

λΌλŠ” ꡬ절이 μžˆμŠ΅λ‹ˆλ‹€.

IoCλΌλŠ” 단어가 λ„ˆλ¬΄ λͺ¨ν˜Έν•˜μ—¬ κ·Έλƒ₯ μ•žμœΌλ‘œλŠ” **DI(Dependency injection)**μ΄λΌλŠ” 단어λ₯Ό μ‚¬μš©ν•˜μžκ³  ν•˜μ˜€μœΌλ‹ˆκΉŒ 이번 μ •λ¦¬μ—μ„œλŠ” κ·Έλƒ₯ λͺ¨λ‘ 톡틀어 DI라고 λ§ν• κ²Œμš”

1. koinμ΄λž€?

Koin은 DSL둜 이루어진 μ˜μ‘΄μ„± μ£Όμž… ν”„λ ˆμž„μ›Œν¬μž…λ‹ˆλ‹€.

λͺ¨λ‘ λ‹€ μ½”ν‹€λ¦°μœΌλ‘œ μž‘μ„±λ˜μ—ˆκ³ , μ½”ν‹€λ¦°μœΌλ‘œλ§Œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

1-1. Daggerμ™€μ˜ 차이점

DaggerλŠ” μ–΄λ…Έν…Œμ΄μ…˜, 클래슀 기반으둜 μ•½κ°„ 가독성이 λ–¨μ–΄μ§€μ§€λ§Œ, μ–΄λ…Έν…Œμ΄μ…˜ ν”„λ‘œμ„Έμ„œλ₯Ό μ΄μš©ν•˜μ—¬ 컴파일 λ‹¨μœ„μ—μ„œ 였λ₯˜λ₯Ό μž‘μ•„λ‚Ό 수 μžˆμŠ΅λ‹ˆλ‹€.

koin은 DSL 기반으둜 이루어져 μžˆμ–΄ 가독성이 μ’‹κ³ , 객체λ₯Ό μ£Όμž…ν•  λ•Œ byλ₯Ό μ΄μš©ν•˜μ—¬ 지연 방식을 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ 였λ₯˜λ₯Ό μ»΄νŒŒμΌμ—μ„œ μž‘μ•„λ‚Ό 수 μ—†κ³  λŸ°νƒ€μž„μ—μ„œ 였λ₯˜λ₯Ό μž‘μ•„λ‚Ό 수 μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ, μ„œλΉ„μŠ€ λ‘œμΌ€μ΄ν„° νŒ¨ν„΄μ„ μ‚¬μš©ν•©λ‹ˆλ‹€.

1-2. Module

koinμ—μ„œλŠ” Module에 ν•„μš”ν•œ μ˜μ‘΄μ„±μ„ μ •μ˜ν•˜λ©° μ„€κ³„ν•©λ‹ˆλ‹€.

λͺ¨λ“ˆμ„ μ •μ˜ν•˜λŠ”λ²•μ€ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

val module = module {
    
}

module도 λ§ˆμ°¬κ°€μ§€λ‘œ DSL ν˜•μ‹μœΌλ‘œ μ‚¬μš©ν•  수 있기 λ•Œλ¬Έμ—, 가독성이 λ†’μŠ΅λ‹ˆλ‹€.

λͺ¨λ“ˆμ„ μ •μ˜ν•˜κ³ , λͺ¨λ“ˆ μ•ˆμ— λ“€μ–΄κ°ˆ μ˜μ‘΄μ„±μ„ μ •μ˜ν•©λ‹ˆλ‹€.

1-3. μ˜μ‘΄μ„± μ •μ˜

λͺ¨λ“ˆ μ•ˆμ—μ„œ μ˜μ‘΄μ„±μ„ μ •μ˜ν•˜κ³ , 차후에 ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ inject(), viewModel()λ“±μ˜ ν‚€μ›Œλ“œλ₯Ό μ΄μš©ν•˜μ—¬ λͺ¨λ“ˆλ‘œλΆ€ν„° μ˜μ‘΄μ„±μ„ μ£Όμž…λ°›μŠ΅λ‹ˆλ‹€.

μ‚¬μš©ν•  수 μžˆλŠ” ν‚€μ›Œλ“œλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

  1. factory: inject() κ°€ 호좜될 λ•Œ λ§ˆλ‹€ μƒˆλ‘œμš΄ 객체λ₯Ό λ§Œλ“€μ–΄μ€λ‹ˆλ‹€.
  2. single: inject()κ°€ 호좜될 λ•Œ, 싱글톀 객체λ₯Ό μ£Όμž…ν•΄μ€λ‹ˆλ‹€.
  3. viewModel: AAC의 ViewModel을 μ‚¬μš©ν•  λ•Œ μ“°λŠ” ν‚€μ›Œλ“œλ‘œ, ViewModelProvidersλ₯Ό ν†΅ν•˜μ—¬ 생λͺ…주기에 μ•ˆμ „ν•œ ViewModel을 μ£Όμž…ν•΄μ€λ‹ˆλ‹€.
  4. get(): λͺ¨λ“ˆμ—μ„œ 각 μ»΄ν¬λ„ŒνŠΈλΌλ¦¬μ˜ μ˜μ‘΄μ„± μ£Όμž…μ„ μœ„ν•΄ μ“°μ΄λŠ” ν‚€μ›Œλ“œμž…λ‹ˆλ‹€.

이외에도 μ—¬λŸ¬ ν‚€μ›Œλ“œλ₯Ό ν†΅ν•΄μ„œ μ˜μ‘΄μ„±μ„ μ •μ˜ν•˜κ³ , ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ μ˜μ‘΄μ„±μ„ μ£Όμž…ν•©λ‹ˆλ‹€.

1-4. μ˜μ‘΄μ„± μ£Όμž…ν•˜κΈ°

λͺ¨λ“ˆμ—μ„œ μ •μ˜ν•œ μ˜μ‘΄μ„±μ„ ν•„μš”ν•œ 곳에 μ£Όμž…ν•©λ‹ˆλ‹€. Dagger2와 달리 μœ„μž„ ν”„λ‘œνΌν‹°λ₯Ό μ‚¬μš©ν•  μˆ˜λ„ 있고, κ·Έλƒ₯ λ°›μ•„μ˜¬ μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

μ‚¬μš©ν•˜λŠ” ν‚€μ›Œλ“œλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

  1. by inject(): μœ„μž„ ν”„λ‘œνΌν‹°λ₯Ό μ΄μš©ν•˜μ—¬ 호좜될 μ‹œμ μ— μ˜μ‘΄μ„±μ„ μ£Όμž…λ°›μŠ΅λ‹ˆλ‹€.
  2. by viewModel() : μœ„μž„ ν”„λ‘œνΌν‹°λ₯Ό μ΄μš©ν•˜μ—¬ 호좜될 μ‹œμ μ— λ·°λͺ¨λΈμ„ μ£Όμž…λ°›μŠ΅λ‹ˆλ‹€. λͺ¨λ“ˆμ—μ„œ viewModel을 μ •μ˜ν–ˆμ„ λ•Œ μ‚¬μš©ν•©λ‹ˆλ‹€.
  3. by sharedViewModel(): μœ„μ™€ 같은 λ™μž‘μ„ μˆ˜ν–‰ν•˜μ§€λ§Œ, ν”„λž˜κ·Έλ¨ΌνŠΈμ—μ„œλ§Œ μ‚¬μš©ν•  수 있고 μ•‘ν‹°λΉ„ν‹° μ•„λž˜μ—μ„œ κ³΅μœ ν•  수 μžˆλŠ” λ·°λͺ¨λΈμ„ μ£Όμž…λ°›μŠ΅λ‹ˆλ‹€.
  4. getViewModel(), getSharedViewModel(): μœ„μž„ ν”„λ‘œνΌν‹°λ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šκ³ , μœ„μ˜ μΉœκ΅¬λ“€μ„ κ·Έλƒ₯ λ°”λ‘œ λ°›μ•„μ˜΅λ‹ˆλ‹€.

2. koin μ‹œμž‘ν•΄λ³΄κΈ°

지~λ‚œλ²ˆμ— μ˜ˆμ‹œλ‘œ λ“€μ—ˆλ˜ MVP μ½”λ“œμ— koin을 μ μš©ν•΄λ΄…μ‹œλ‹€~~

2-1. μ˜μ‘΄μ„± μΆ”κ°€ν•˜κΈ°

def koin_version = '1.0.1'

// Koin for Android
implementation "org.koin:koin-android:$koin_version"
// Koin Android Scope feature
implementation "org.koin:koin-android-scope:$koin_version"
// Koin Android ViewModel feature
implementation "org.koin:koin-android-viewmodel:$koin_version"
  1. λͺ¨λ“ˆ λ‹¨μœ„ build.gradle의 dependencies에 μœ„μ™€ 같은 μ˜μ‘΄μ„±μ„ μΆ”κ°€ν•©λ‹ˆλ‹€.
  2. μ‹±ν¬ν•˜λ©΄ μ™„μ„±~~

2-2. λͺ¨λ“ˆ μ •μ˜ν•˜κΈ°

val mainModule = module {
    factory { MainPresenter(get()) }
    single { MainRepository() }
}

class MainPresenter(val repository: MainRepository) : MainContract.Presenter {
    
}
  1. μ½”ν‹€λ¦°μ—μ„œλŠ” κΌ­ 클래슀λ₯Ό λ§Œλ“€ ν•„μš”κ°€ μ—†κΈ° λ•Œλ¬Έμ—, 클래슀λ₯Ό μ •μ˜ν•˜μ§€ μ•Šκ³  파일만 λ§Œλ“€μ–΄ 그곳에 λͺ¨λ“ˆλ“€μ„ μ •μ˜ν•˜λŠ” 방법을 μ‚¬μš©ν•©λ‹ˆλ‹€.

  2. MainActivityμ—μ„œ MainPresenter μ˜μ‘΄μ„±μ„ 받아와야 ν•˜κΈ° λ•Œλ¬Έμ— mainModule에 MainPresnterλ₯Ό μ •μ˜ν•©λ‹ˆλ‹€.

  3. ν”„λ ˆμ  ν„°λŠ” factory ν‚€μ›Œλ“œλ₯Ό μ΄μš©ν•˜μ—¬, inject() κ°€ 호좜될 λ•Œ λ§ˆλ‹€ μƒˆλ‘œμš΄ 객체λ₯Ό λ°›μ•„μ˜€κ²Œλ” ν–ˆμŠ΅λ‹ˆλ‹€.

  4. λ ˆν¬μ§€ν† λ¦¬ ν΄λž˜μŠ€λŠ” single ν‚€μ›Œλ“œλ₯Ό μ΄μš©ν•˜μ—¬ μ‹±κΈ€ν†€μœΌλ‘œ μ •μ˜ν•©λ‹ˆλ‹€.

  5. MainPresenterλŠ” μƒμ„±μžλ‘œ MainRepositoryλ₯Ό λ°›μŠ΅λ‹ˆλ‹€. μ˜μ‘΄μ„±μ— get() ν‚€μ›Œλ“œλ₯Ό μƒμ„±μž μ•ˆμ— μž‘μ„±ν•΄λ‘λ©΄ koin이 μ•Œμ•„μ„œ μ˜μ‘΄μ„±μ„ μ°Ύμ•„μ„œ λ„£μ–΄μ€λ‹ˆλ‹€.

2-3. Application μ •μ˜ν•˜κΈ°

Application을 μƒμ†λ°›λŠ” 클래슀λ₯Ό λ§Œλ“€κ³ , onCreate()에 startKoin() 을 μž‘μ„±ν•©λ‹ˆλ‹€.

class App : Application() {
    override fun onCreate() {
        super.onCreate()
        startKoin(this, listOf(mainModule))
    }
}

startKoin()의 μΈμžμ—λŠ” context와 μ •μ˜ν•΄λ‘” λͺ¨λ“ˆ λ¦¬μŠ€νŠΈκ°€ λ“€μ–΄κ°‘λ‹ˆλ‹€.

this와 listof ν‚€μ›Œλ“œλ₯Ό μ΄μš©ν•˜κ±°λ‚˜, 미리 μ •μ˜ν•΄λ‘” λͺ¨λ“ˆ 리슀트λ₯Ό 인자둜 λ„£μ–΄μ€λ‹ˆλ‹€.

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:name=".App"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

κ·Έ λ‹€μŒμ— λ©”λ‹ˆνŽ˜μŠ€νŠΈμ˜ μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜ νƒœκ·Έμ— android:name 속성에 방금 λ§Œλ“  μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ„ μ •μ˜ν•΄μ€λ‹ˆλ‹€.

2-4. μ˜μ‘΄μ„± μ£Όμž…λ°›κΈ°

class MainActivity : AppCompatActivity(), MainContract.View {

    val presenter: MainPresenter by inject()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        presenter.view = this
    }
}

μ •μ˜ν•΄λ‘” λͺ¨λ“ˆμ„ by inject()λ₯Ό μ΄μš©ν•˜μ—¬ μ£Όμž…λ°›μŠ΅λ‹ˆλ‹€.

와! λμž…λ‹ˆλ‹Ή~~