Slide 1

Slide 1 text

Pluu Android Developer GDG Korea Android Organizer in Yanolja Android + DI + KOIN = Easy?!

Slide 2

Slide 2 text

Pluu Dev. 2 DIী ؀ೠ ҙब ߊ಴ POINT. 01 02 03 KOIN ਵ۽ оߺѱ द੘ ࢜۽਍ Ѫী ؀ೠ ࢤп

Slide 3

Slide 3 text

Pluu Dev. 3 Introduction INDEX. 01 02 03 04 05 What’s KOIN Use KOIN KOIN in Android Pros / Cons 3

Slide 4

Slide 4 text

Pluu Dev. 4 Instance Injection ⇪ ⇪ ⇪ new new new new new new ੉ٸ ೙ਃೠ DI Dagger V2 ֫਷ ੋ૑ب / উ੹ೠ ֫਷ ૓ੑ դ੉ب … … … оߺѱ द੘ ਋ࢶ KOIN

Slide 5

Slide 5 text

Pluu Dev. Open/ closed Liskov substitution Interface segregation Dependency inversion D I L O S Single responsibility https://ko.wikipedia.org/wiki/SOLID_(ё୓_૑ೱ_ࢸ҅) 5

Slide 6

Slide 6 text

Pluu Dev. 6 DI

Slide 7

Slide 7 text

Pluu Dev. 7 Dependency Injection

Slide 8

Slide 8 text

http://sys1yagi.hatenablog.com/entry/2017/06/24/220951 Android Clean Architecture
 (Add Feature)

Slide 9

Slide 9 text

Pluu Dev. 9

Slide 10

Slide 10 text

Pluu Dev. 10

Slide 11

Slide 11 text

Pluu Dev. What’s KOIN. 11

Slide 12

Slide 12 text

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!"

Slide 13

Slide 13 text

Pluu Dev. KOIN 1.0.0 Unleashed
 (18.09.14)

Slide 14

Slide 14 text

Pluu Dev. 14 Support

Slide 15

Slide 15 text

Pluu Dev. Sample. 15

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

Pluu Dev. KOIN DSL. 17

Slide 18

Slide 18 text

Pluu Dev. Setup // Add Jcenter to your repositories if needed repositories { jcenter() } dependencies { // Koin for Kotlin apps compile 'org.koin:koin-core:{revnumber}' } 18

Slide 19

Slide 19 text

Pluu Dev. KOIN DSL 19 module Koin Module ੿੄ factory Instance ࢤࢿ single Singleton Instance ࢤࢿ get Dependency Component ೧Ѿ bind Bind ఋੑ ੿੄

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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 { ServiceImpl() } } https://insert-koin.io/docs/1.0/documentation/koin-core/index.html#_binding_an_interface

Slide 24

Slide 24 text

Pluu Dev. Use KOIN. 24

Slide 25

Slide 25 text

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()) } }

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

Pluu Dev. Naming a definition val myModule = module { single { ServiceImpl() } single { ServiceImpl() } } val service : Service by inject() 28

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

Pluu Dev. Naming a definition val myModule = module { single("default") { ServiceImpl() } single("test") { ServiceImpl() } } val service : Service by inject(name = "default") 30

Slide 31

Slide 31 text

Pluu Dev. Dealing with generics module { single { ArrayList() } single { ArrayList() } } 31

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

Pluu Dev. Dealing with generics module { single(name = "Ints") { ArrayList() } single(name = "Strings") { ArrayList() } } 33

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

Pluu Dev. startKoin startKoin(listOf(module1,module2 ...)) 35

Slide 36

Slide 36 text

Pluu Dev. startKoin fun startKoin( list: List, useEnvironmentProperties: Boolean = false, useKoinPropertiesFile: Boolean = false, extraProperties: Map = HashMap(), logger: Logger = PrintLogger() ) 36

Slide 37

Slide 37 text

Pluu Dev. startKoin fun startKoin( list: List, useEnvironmentProperties: Boolean = false, useKoinPropertiesFile: Boolean = false, extraProperties: Map = HashMap(), logger: Logger = PrintLogger() ) 37 Modules Koin Logger

Slide 38

Slide 38 text

Pluu Dev. Modules & Namespaces. 38

Slide 39

Slide 39 text

Pluu Dev. 39 KOIN Module. Koin ੿੄ܳ ೞח "ҕр"

Slide 40

Slide 40 text

Pluu Dev. Module’s Path fun module( path: String = Path.ROOT, createOnStart: Boolean = false, override: Boolean = false, definition: ModuleDefinition.() -> Unit ) 40 Path

Slide 41

Slide 41 text

Pluu Dev. Modules with paths // definitions in / (root) namespace val aRootModule = module { ... } // definitions in /org/sample namespace val sampleModule = module("org.sample") { ... } 41

Slide 42

Slide 42 text

Pluu Dev. Modules with paths 42 Root Path Definition Sub Path

Slide 43

Slide 43 text

Pluu Dev. 43 ALL EQUALS module { module("org.sample") { // ... } } module("org.sample") { // … } module { module("org") { module("sample") { // ... } } }

Slide 44

Slide 44 text

Pluu Dev. Implicit definitions naming val aModule = module { module { single { ComponentA() } single { ComponentB(get()) } } module { single { ComponentA() } single { ComponentC(get()) } } } 44 Empty

Slide 45

Slide 45 text

Pluu Dev. Directly get( name = "B.ComponentA" ) Implicit definitions naming val aModule = module { module("B") { single { ComponentA() } single { ComponentB(get()) } } module("C") { single { ComponentA() } single { ComponentC(get()) } } } 45

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

Pluu Dev. Start the container. 48

Slide 49

Slide 49 text

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): Koin 49

Slide 50

Slide 50 text

Pluu Dev. Stop Koin - closing all resources fun stopKoin() 50

Slide 51

Slide 51 text

Pluu Dev. Properties. 51

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

Pluu Dev. KOIN Components. 53

Slide 54

Slide 54 text

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.

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

Pluu Dev. Unlock the Koin API with KoinComponents 57 by inject() Koin ஶప੉ց੄ ੋझఢझ ૑ো ஂٙ get() Koin ஶప੉ց੄ ੋझఢझ ஂٙ release() ݽٕ੄ ੋझఢझ ೧ઁ getProperty() / 
 setProperty() Property get/set

Slide 58

Slide 58 text

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( name = "ComponentB.ComponentA" ) val a_c = get( name = "ComponentC.ComponentA" )

Slide 59

Slide 59 text

Pluu Dev. Injection parameters. 59

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

Pluu Dev. 61 KOIN in Android

Slide 62

Slide 62 text

Pluu Dev. Setup // Add Jcenter to your repositories if needed repositories { jcenter() } dependencies { // Koin for Android compile 'org.koin:koin-android:{revnumber}' } 62

Slide 63

Slide 63 text

Pluu Dev. Start Koin class MyApplication : Application() { override fun onCreate() { super.onCreate() // Start Koin startKoin(this, listOf(appModule)) } } 63

Slide 64

Slide 64 text

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 ੋझఢझܳ Ѩ࢝ оמ

Slide 65

Slide 65 text

Pluu Dev. ViewModel. 65

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

Pluu Dev. Injecting your ViewModel 67 by viewModel() Lazy Delegate Propertyܳ ࢎਊೞৈ ViewModel Injection getViewModel() ૒੽ ViewModel ੋझఢझܳ ஂٙ sharedViewModel() Lazy Delegate Property۽ ҕਬ ViewModel Injection getSharedViewModel() ҕਬ ViewModel ੋझఢझܳ ૒੽ ஂٙ

Slide 68

Slide 68 text

Pluu Dev. Create a ViewModel class class MyViewModel(val repo : HelloRepository) : ViewModel() { fun sayHello() = "${repo.giveHello()} from $this" } 68

Slide 69

Slide 69 text

Pluu Dev. Writing the Koin module val appModule = module { // single instance of HelloRepository single { HelloRepositoryImpl() } // MyViewModel ViewModel viewModel { MyViewModel(get()) } } 69

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

Pluu Dev. Injecting dependencies class WeatherActivity : AppCompatActivity() { /** Declare WeatherViewModel with Koin and allow constructor dependency injection */ private val viewModel by viewModel() } class WeatherFragment : Fragment() { /** Declare shared WeatherViewModel with WeatherActivity */ private val viewModel by sharedViewModel() } 71

Slide 72

Slide 72 text

Pluu Dev. 72 ■ औҊ ૒ҙ੸ ■ Logger ઓ੤ ■ ೐۾द, ௏٘ ࢤࢿ, Reflection ޷ࢎਊ ■ Fast Build CONS PROS ■ Service Locator Pattern ■ Overhead ■ Runtime Error ■ Constructor Injection Not Support

Slide 73

Slide 73 text

Pluu Dev. Easy 73 Moving from Dagger to Koin — Simplify your Android development

Slide 74

Slide 74 text

Pluu Dev. Logger (1/2) 74 https://github.com/InsertKoinIO/koin/tree/master/koin-projects/examples/coffee-maker

Slide 75

Slide 75 text

Pluu Dev. Logger (2/2) 75 https://github.com/InsertKoinIO/koin/tree/master/koin-projects/examples/coffee-maker

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

Pluu Dev. 78 https://martinfowler.com/articles/injection.html ■ != Dependency Injection Pattern ■ Factory Patternҗ ࠺त Service Locator Pattern Instance Injection

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

Pluu Dev. 80 Introduction ؊ Ө਷ షۿ਷ Reddit

Slide 81

Slide 81 text

Pluu Dev. 81 Dagger KOIN BEST RESULT? Developer / Architecture / Setting / Search / Testability / Scalability / etc

Slide 82

Slide 82 text

Pluu Dev. 82 STEP Module Search Refactoring startKoin & injection Step 01 Step 02 Step 03

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

THANK YOU FOR WATCHING! ANY QUESTIONS?