본문
180911(화) - Koin
Koin
Gradle setup
- RC version 이지만, 9월 중 릴리즈 버전 나온다고 함
// Add Jcenter to your repositories if needed repositories { jcenter() } dependencies { // Koin for Kotlin apps compile 'org.koin:koin-core:1.0.0-RC-3' // Testing testCompile 'org.koin:koin-test:1.0.0-RC-3' }
Component
interface HelloRepository {
fun giveHello(): String
}
class HelloRepositoryImpl() : HelloRepository {
override fun giveHello() = "Hello Koin"
}
class MySimplePresenter(val repo: HelloRepository) {
fun sayHello() = "${repo.giveHello()} from $this"
}
Module
Note : MySimplePresenter class as factory는 new instance each time our Activity will need one.
- single {...} 은 singleton instance 생성
val appModule = module {
// single instance of HelloRepository
single<HelloRepository> { HelloRepositoryImpl() }
// Simple Presenter Factory
factory { MySimplePresenter(get()) }
}
val helloModule = module {
single { HelloMessageData() }
single { HelloServiceImpl(get()) as HelloService }
}
Start Koin
Android
- Application이 꼭 필요한지는 더 알아봐야 함.
- 만약 필요하다면, vertical plugin쪽에서 dagger와 똑같이 문제가 될 수 있음
→ https://github.com/InsertKoinIO/koin/issues/156
・ 해당 issues를 누군가 제보했고, rework version이 merged됨
(https://github.com/InsertKoinIO/koin/pull/158)
→ 하지만 startKoin(...) 을 중복 사용할 가능성이 있으니 주의 필요.
class MyApplication : Application(){
override fun onCreate() {
super.onCreate()
// Start Koin
startKoin(this, listOf(appModule))
}
}
Kotlin
- 특이하게 Application 에서 KoinComponent interface implements
- 마찬가지로 Application 이 필요한지는 의문
/**
* HelloApplication - Application Class
* use HelloService
*/
class HelloApplication : KoinComponent {
// Inject HelloService
val helloService by inject<HelloService>()
// display our data
fun sayHello() = println(helloService.hello())
}
fun main(vararg args: String) {
startKoin(listOf(helloModule))
HelloApplication().sayHello()
}
Injecting dependencies
- MySimplePresenter 는 will be created HelloRepository instance
- get() function은 instance를 directly retrieve (non-lazy)
class MySimpleActivity : AppCompatActivity() {
// Lazy injected MySimplePresenter
val firstPresenter: MySimplePresenter by inject()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//...
}
}
AAC & ViewModel
- koin will give a ViewModel to the lifecycle ViewModelFactory and help bind to the current compoent
// Add Jcenter to your repositories if needed
repositories {
jcenter()
}
dependencies {
// Koin for Android - Scope feature
// include koin-android-scope & koin-android
compile 'org.koin:koin-android-viewmodel:1.0.0-RC-3'
}
interface HelloRepository {
fun giveHello(): String
}
class HelloRepositoryImpl() : HelloRepository {
override fun giveHello() = "Hello Koin"
}
class MyViewModel(val repo : HelloRepository) : ViewModel() {
fun sayHello() = "${repo.giveHello()} from $this"
}
val appModule = module {
// single instance of HelloRepository
single<HelloRepository> { HelloRepositoryImpl() }
// MyViewModel ViewModel
viewModel { MyViewModel(get()) }
}
class MyViewModelActivity : AppCompatActivity() {
// Lazy Inject ViewModel
val myViewModel: MyViewModel by viewModel()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_simple)
//...
}
}
Scope
- bindScope(..) : bind current lifecycle. Activity의 lifecycle이 ends되면, close the associated scope and injected instance
// Add Jcenter to your repositories if needed
repositories {
jcenter()
}
dependencies {
// Koin for Android - Scope feature
// include koin-android
compile 'org.koin:koin-android-scope:1.0.0-RC-3'
}
interface HelloRepository {
fun giveHello(): String
}
class HelloRepositoryImpl() : HelloRepository {
override fun giveHello() = "Hello Koin"
}
class MyScopePresenter(val repo: HelloRepository) {
fun sayHello() = "${repo.giveHello()} from $this"
}
val appModule = module {
// single instance of HelloRepository
single<HelloRepository> { HelloRepositoryImpl() }
// Scoped MyScopePresenter instance
scope("session") { MyScopePresenter(get())}
}
class MyScopeActivity : AppCompatActivity() {
// inject MyScopePresenter from "session" scope
val scopePresenter: MyScopePresenter by inject()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_simple)
// bind "session" scope to component lifecycle
bindScope(getOrCreateScope("session"))
//...
}
}
JUnit Tests
- closeKoin() : close Koin context
// Add Jcenter to your repositories if needed
repositories {
jcenter()
}
dependencies {
// Koin testing tools
testcompile 'org.koin:koin-test:1.0.0-RC-3'
}
val helloModule = module {
single { HelloMessageData() }
single { HelloServiceImpl(get()) as HelloService }
}
class HelloAppTest : KoinTest() {
val model by inject<HelloMessageData>()
val service by inject<HelloService>()
@Before
fun before() {
startKoin(listOf(helloModule))
}
@After
fun after() {
closeKoin()
}
@Test
fun tesKoinComponents() {
val helloApp = HelloApplication()
helloApp.sayHello()
assertEquals(service, helloApp.helloService)
assertEquals("Hey, ${model.message}", service.hello())
}
}
'Mobile > DI' 카테고리의 다른 글
180918(화) - Koin (Koin docs) (0) | 2018.09.18 |
---|---|
180423(월) - Dagger (User's Guide) (0) | 2018.04.23 |
170713(목) - Kotlin & Dagger2 crash (0) | 2017.07.13 |
170712(수) - Dependency Injection with Dagger2 (0) | 2017.07.12 |
170707(금) - android-architecture-todo-mvp-dagger (0) | 2017.07.07 |
댓글