Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Android + DI + Koin = Easy?!

Android + DI + Koin = Easy?!

2018년 11월 25일
"우리는 안드로이드 개발자입니다"에서 발표한 자료입니다

pluulove (노현석)

November 25, 2018
Tweet

More Decks by pluulove (노현석)

Other Decks in Programming

Transcript

  1. Pluu Dev. 2 DIী ؀ೠ ҙब ߊ಴ POINT. 01 02

    03 KOIN ਵ۽ оߺѱ द੘ ࢜۽਍ Ѫী ؀ೠ ࢤп
  2. Pluu Dev. 3 Introduction INDEX. 01 02 03 04 05

    What’s KOIN Use KOIN KOIN in Android Pros / Cons 3
  3. Pluu Dev. 4 Instance Injection ⇪ ⇪ ⇪ new new

    new new new new ੉ٸ ೙ਃೠ DI Dagger V2 ֫਷ ੋ૑ب / উ੹ೠ ֫਷ ૓ੑ դ੉ب … … … оߺѱ द੘ ਋ࢶ KOIN
  4. Pluu Dev. Open/ closed Liskov substitution Interface segregation Dependency inversion

    D I L O S Single responsibility https://ko.wikipedia.org/wiki/SOLID_(ё୓_૑ೱ_ࢸ҅) 5
  5. Pluu Dev. KOIN 12 "A pragmatic lightweight dependency injection framework

    for Kotlin developers. Written in pure Kotlin using functional resolution only: no proxy, no code generation, no reflection!"
  6. Pluu Dev. class Repository() class View() class Presenter( val repository

    : Repository ) Define val appModule = module { single { Repository() } module("view") { factory { View() } factory { Presenter(get()) } } } Sample 16 class MyApplication : Application() { override fun onCreate() { super.onCreate() startKoin(this, listOf(appModule)) } } class MySimpleActivity : AppCompatActivity() { val firstPresenter: MySimplePresenter by inject() } Module Start Inject
  7. Pluu Dev. Setup // Add Jcenter to your repositories if

    needed repositories { jcenter() } dependencies { // Koin for Kotlin apps compile 'org.koin:koin-core:{revnumber}' } 18
  8. Pluu Dev. KOIN DSL 19 module Koin Module ੿੄ factory

    Instance ࢤࢿ single Singleton Instance ࢤࢿ get Dependency Component ೧Ѿ bind Bind ఋੑ ੿੄
  9. Pluu Dev. Define class Repository() class View() class Presenter( val

    repository : Repository ) 20 val appModule = module { single { Repository() } module("view") { factory { View() } factory { Presenter(get()) } } } https://gist.github.com/arnaudgiuliani/d343df6e08a997b2ff29f7542ca1f601#file-koin_1-0_dsl-kt
  10. Pluu Dev. val appModule = module { single { Repository()

    } module("view") { factory { View() } factory { Presenter(get()) } } } Define 21 Module ੿੄ Singletone Sub Module Factory Instance Factory Instance - Injection
  11. Pluu Dev. Define - Log 22 [context] create [module] declare

    Single [name='Repository',class='Repository'] [module] declare Factory [name='view.View',class='View', path:'view'] [module] declare Factory [name='view.Presenter',class='Presenter', path:'view'] [modules] loaded 3 definitions
  12. Pluu Dev. Binding an interface interface Service { fun doSomething()

    } class ServiceImpl : Service { override fun doSomething() { ... } } 23 val myModule = module { single { ServiceImp() } single { ServiceImpl() as Service } single<Service> { ServiceImpl() } } https://insert-koin.io/docs/1.0/documentation/koin-core/index.html#_binding_an_interface
  13. Pluu Dev. Binding an interface class TestA(val service: Service) class

    TestB(val service: ServiceImpl) 25 val myModule = module { single { ServiceImpl() } factory { TestA(get()) } factory { TestB(get()) } }
  14. Pluu Dev. (KOIN)::[e] Error while resolving instance for class 'Service'

    - error: org.koin.error.NoBeanDefFoundException: No compatible definition found for type 'Service'. Check your module definition (KOIN)::[e] Error while resolving instance for class 'TestA' - error: org.koin.error.BeanInstanceCreationException: Can't create definition for 'Factory [name='TestA',class='TestA']' due to error : No compatible definition found for type 'Service'. Check your module definition 26 Binding an interface
  15. Pluu Dev. class TestA(val service: Service) class TestB(val service: ServiceImpl)

    val myModule = module { single { ServiceImpl() } factory { TestA(get()) } factory { TestB(get()) } } bind Service::class Binding an interface 27
  16. Pluu Dev. Naming a definition val myModule = module {

    single<Service> { ServiceImpl() } single<Service> { ServiceImpl() } } val service : Service by inject() 28
  17. Pluu Dev. Exception in thread "main" org.koin.error.BeanOverrideException: Try to override

    definition with Single [name='ServiceImpl',class='ServiceImpl'], but override is not allowed. Use 'override' option in your definition or module. 29 Naming a definition
  18. Pluu Dev. Naming a definition val myModule = module {

    single<Service>("default") { ServiceImpl() } single<Service>("test") { ServiceImpl() } } val service : Service by inject(name = "default") 30
  19. Pluu Dev. Exception in thread "main" org.koin.error.BeanOverrideException: Try to override

    definition with Single [name='ArrayList',class='java.util.ArrayList'], but override is not allowed. Use 'override' option in your definition or module. 32 Dealing with generics
  20. Pluu Dev. Dealing with generics module { single(name = "Ints")

    { ArrayList<Int>() } single(name = "Strings") { ArrayList<String>() } } 33
  21. Pluu Dev. Declaring injection parameters class Presenter(val view : View)

    val myModule = module { single{ (view : View) -> Presenter(view) } } val presenter : Presenter by inject { parametersOf(view) } 34
  22. Pluu Dev. startKoin fun startKoin( list: List<Module>, useEnvironmentProperties: Boolean =

    false, useKoinPropertiesFile: Boolean = false, extraProperties: Map<String, Any> = HashMap(), logger: Logger = PrintLogger() ) 36
  23. Pluu Dev. startKoin fun startKoin( list: List<Module>, useEnvironmentProperties: Boolean =

    false, useKoinPropertiesFile: Boolean = false, extraProperties: Map<String, Any> = HashMap(), logger: Logger = PrintLogger() ) 37 Modules Koin Logger
  24. Pluu Dev. Module’s Path fun module( path: String = Path.ROOT,

    createOnStart: Boolean = false, override: Boolean = false, definition: ModuleDefinition.() -> Unit ) 40 Path
  25. Pluu Dev. Modules with paths // definitions in / (root)

    namespace val aRootModule = module { ... } // definitions in /org/sample namespace val sampleModule = module("org.sample") { ... } 41
  26. Pluu Dev. 43 ALL EQUALS module { module("org.sample") { //

    ... } } module("org.sample") { // … } module { module("org") { module("sample") { // ... } } }
  27. Pluu Dev. Implicit definitions naming val aModule = module {

    module { single { ComponentA() } single { ComponentB(get()) } } module { single { ComponentA() } single { ComponentC(get()) } } } 44 Empty
  28. Pluu Dev. Directly get<ComponentA>( name = "B.ComponentA" ) Implicit definitions

    naming val aModule = module { module("B") { single { ComponentA() } single { ComponentB(get()) } } module("C") { single { ComponentA() } single { ComponentC(get()) } } } 45
  29. Pluu Dev. Linking definitions between modules // ComponentB <- ComponentA

    class ComponentA() class ComponentB(val componentA : ComponentA) val moduleA = module { single { ComponentA() } } val moduleB = module { single { ComponentB(get()) } } 46
  30. Pluu Dev. Visibility rules // definitions in / val rootModule

    = module { single { ComponentA() } } // definitions in /org val orgModule = module("org") { single { ComponentB(...) } } // definitions in /org/sample val sampleModule = module("org.sample") { single { ComponentC(...) } } // definitions in /org/demo val demoModule = module("org.demo") { single { ComponentD(...) } } 47 CC /sample CA /org CB CD /demo
  31. Pluu Dev. Loading modules without startKoin function /** * Load

    Koin modules - whether Koin is already started or not * allow late module definition load (e.g: libraries ...) * * @param modules : List of Module */ fun loadKoinModules(modules: List<Module>): Koin 49
  32. Pluu Dev. Read/Write property from a KoinComponent class MyComponent :

    KoinComponent { fun doSomething() { // Read a Koin property val serviceUrl = getProperty("server_url") // Set a Koin property setProperty("isDebug",false) } } 52 Read Write
  33. Pluu Dev. 54 KOIN Components. What we need now is

    an API to retrieve our instances outside of the container. That’s the goal of Koin components.
  34. Pluu Dev. Start Koin with myModule fun main(vararg args :

    String) { // Start Koin startKoin(listOf(myModule)) // Create MyComponent instance and inject from Koin container MyComponent() } 55
  35. Pluu Dev. Use get() & by inject() to inject MyService

    instance class MyComponent : KoinComponent { // lazy inject Koin instance val myService : MyService by inject() // or // eager inject Koin instance val myService : MyService get() } 56
  36. Pluu Dev. Unlock the Koin API with KoinComponents 57 by

    inject() Koin ஶప੉ց੄ ੋझఢझ ૑ো ஂٙ get() Koin ஶప੉ց੄ ੋझఢझ ஂٙ release() ݽٕ੄ ੋझఢझ ೧ઁ getProperty() / 
 setProperty() Property get/set
  37. Pluu Dev. Resolving instance from a name or a module

    val module = module { module("ComponentB") { single { ComponentA() } single { ComponentB(get()) } } module("ComponentC") { single { ComponentA() } single { ComponentC(get()) } } } 58 class ComponentA class ComponentB(
 val componentA: ComponentA) class ComponentC(
 val componentA: ComponentA) val a_b = get<ComponentA>( name = "ComponentB.ComponentA" ) val a_c = get<ComponentA>( name = "ComponentC.ComponentA" )
  38. Pluu Dev. Multiple parameters class Presenter(val view : View, id

    : String) val myModule = module { single { (view : View, id : String) -> Presenter(view, id) } } class MyComponent : View, KoinComponent { val id : String ... // inject with view & id val presenter : Presenter by inject { parametersOf(this, id) } } 60
  39. Pluu Dev. Setup // Add Jcenter to your repositories if

    needed repositories { jcenter() } dependencies { // Koin for Android compile 'org.koin:koin-android:{revnumber}' } 62
  40. Pluu Dev. Start Koin class MyApplication : Application() { override

    fun onCreate() { super.onCreate() // Start Koin startKoin(this, listOf(appModule)) } } 63
  41. Pluu Dev. Injecting dependencies class MySimpleActivity : AppCompatActivity() { //

    Lazy injected MySimplePresenter val firstPresenter: MySimplePresenter by inject() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) //... } } 64 inject() / get() ܳ ా೧ Activity, Fragment, Service ١ Component ীࢲ Koin ੋझఢझܳ Ѩ࢝ оמ
  42. Pluu Dev. Setup // 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:{revnumber}' } 66
  43. Pluu Dev. Injecting your ViewModel 67 by viewModel() Lazy Delegate

    Propertyܳ ࢎਊೞৈ ViewModel Injection getViewModel() ૒੽ ViewModel ੋझఢझܳ ஂٙ sharedViewModel() Lazy Delegate Property۽ ҕਬ ViewModel Injection getSharedViewModel() ҕਬ ViewModel ੋझఢझܳ ૒੽ ஂٙ
  44. Pluu Dev. Create a ViewModel class class MyViewModel(val repo :

    HelloRepository) : ViewModel() { fun sayHello() = "${repo.giveHello()} from $this" } 68
  45. Pluu Dev. Writing the Koin module val appModule = module

    { // single instance of HelloRepository single<HelloRepository> { HelloRepositoryImpl() } // MyViewModel ViewModel viewModel { MyViewModel(get()) } } 69
  46. Pluu Dev. Injecting dependencies class MyViewModelActivity : AppCompatActivity() { //

    Lazy Inject ViewModel val myViewModel: MyViewModel by viewModel() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_simple) //... } } 70
  47. Pluu Dev. Injecting dependencies class WeatherActivity : AppCompatActivity() { /**

    Declare WeatherViewModel with Koin and allow constructor dependency injection */ private val viewModel by viewModel<WeatherViewModel>() } class WeatherFragment : Fragment() { /** Declare shared WeatherViewModel with WeatherActivity */ private val viewModel by sharedViewModel<WeatherViewModel>() } 71
  48. Pluu Dev. 72 ▪ औҊ ૒ҙ੸ ▪ Logger ઓ੤ ▪

    ೐۾द, ௏٘ ࢤࢿ, Reflection ޷ࢎਊ ▪ Fast Build CONS PROS ▪ Service Locator Pattern ▪ Overhead ▪ Runtime Error ▪ Constructor Injection Not Support
  49. Pluu Dev. 76 Fast Module / Compile time Dagger Koin

    :app 41.610s 28.374s :module1 26.363s 19.745s module2 14.345s 11.325s module3 7.241s 3.950s module4 22.828s 5.866s module5 4.976s 2.505s module6 5.631s 4.684 module7 1.988s 3.178s SUM 125.15s 79.59s
  50. Pluu Dev. 77 Overhead 1.1.0 ѐࢶ ৘੿ Injection Time in

    Kotlin Dagger 2.16 Koin 1.0.1 Kodein 5.3.0 Min-Max 0.03-9.48 ms 47.41-7.25 ms 7.48-15.48 ms Average 0.12 ms 60.16 ms 7.63 ms
  51. Pluu Dev. 78 https://martinfowler.com/articles/injection.html ▪ != Dependency Injection Pattern ▪

    Factory Patternҗ ࠺त Service Locator Pattern Instance Injection
  52. Pluu Dev. 79 SEARCH INSTANCE in KOIN 01 02 03

    04 05 79 Target Scope Resolve Instance Module Definition Single / Factory Lazy / Direct Get Declaring Injection Find BeanDefinition
  53. Pluu Dev. 81 Dagger KOIN BEST RESULT? Developer / Architecture

    / Setting / Search / Testability / Scalability / etc
  54. Pluu Dev. ▪ From Dagger to Koin, a step by

    step migration guide ▪ Inversion of Control Containers and the Dependency Injection pattern ▪ Moving from Dagger to Koin — Simplify your Android development ▪ What is dependency injection? ଵҊ 83