Есть ли жизнь без Dagger'a, Михаил Крестьянинов Avito3. ЕСТЬ ЛИ ЖИЗНЬ БЕЗ DAGGER’A?
АГЕНДА
▸DEPENDENCY INJECTION
▸ИНТРО:
▸LIGHTSABER vs KODEIN vs TOOTHPICK
LIGHTSABER
KODEIN
TOOTHPICK
3
10. ЕСТЬ ЛИ ЖИЗНЬ БЕЗ DAGGER’A?
ТЕКУЩАЯ СИТУАЦИЯ НА РЫНКЕ
DAGGER MONOPOLY
7
11. ЕСТЬ ЛИ ЖИЗНЬ БЕЗ DAGGER’A?
АГЕНДА
▸DEPENDENCY INJECTION
▸ИНТРО:
▸LIGHTSABER vs KODEIN vs TOOTHPICK
LIGHTSABER
KODEIN
TOOTHPICK
8
16. ЕСТЬ ЛИ ЖИЗНЬ БЕЗ DAGGER’A?
АГЕНДА
▸DEPENDENCY INJECTION
▸ИНТРО:
▸LIGHTSABER vs KODEIN vs TOOTHPICK
LIGHTSABER
KODEIN
TOOTHPICK
13
21. ЕСТЬ ЛИ ЖИЗНЬ БЕЗ DAGGER’A?
АГЕНДА
▸DEPENDENCY INJECTION
▸ИНТРО:
▸LIGHTSABER vs KODEIN vs TOOTHPICK
LIGHTSABER
KODEIN
TOOTHPICK
18
26. ЕСТЬ ЛИ ЖИЗНЬ БЕЗ DAGGER’A?
АГЕНДА
▸DEPENDENCY INJECTION
▸ИНТРО:
▸LIGHTSABER vs KODEIN vs TOOTHPICK
LIGHTSABER
KODEIN
TOOTHPICK
23
27. ЕСТЬ ЛИ ЖИЗНЬ БЕЗ DAGGER’A? 24
LIGHTSABER
VS
KODEIN
VS
TOOTHPICK
36. val injector = Lightsaber.get()
.createInjector(
AppComponent(app = this)
)
injector.injectMembers(this)
LIGHTSABER
ОСНОВНЫЕ ПРИНЦИПЫ 30
43. ОСНОВНЫЕ ПРИНЦИПЫ
val kodein = Kodein {
import(appModule(this@App))
}
val injector = KodeinInjector()
val prefs: SharedPreferences by injector.instance()
override fun onCreate() {
super.onCreate()
injector.inject(kodein)
}
32
KODEIN
44. ОСНОВНЫЕ ПРИНЦИПЫ
val kodein = Kodein {
import(appModule(this@App))
}
val injector = KodeinInjector()
val prefs: SharedPreferences by injector.instance()
override fun onCreate() {
super.onCreate()
injector.inject(kodein)
}
33
KODEIN
45. ОСНОВНЫЕ ПРИНЦИПЫ
val kodein = Kodein {
import(appModule(this@App))
}
val injector = KodeinInjector()
val prefs: SharedPreferences by injector.instance()
override fun onCreate() {
super.onCreate()
injector.inject(kodein)
}
34
KODEIN
46. ОСНОВНЫЕ ПРИНЦИПЫ
val kodein = Kodein {
import(appModule(this@App))
}
val injector = KodeinInjector()
val prefs: SharedPreferences by injector.instance()
override fun onCreate() {
super.onCreate()
injector.inject(kodein)
}
35
KODEIN
47. ОСНОВНЫЕ ПРИНЦИПЫ
val kodein = Kodein {
import(appModule(this@App))
}
val injector = KodeinInjector()
val prefs: SharedPreferences by injector.instance()
override fun onCreate() {
super.onCreate()
injector.inject(kodein)
}
36
KODEIN
48. ОСНОВНЫЕ ПРИНЦИПЫ
val kodein = Kodein {
import(appModule(this@App))
}
val injector = KodeinInjector()
val prefs: SharedPreferences by injector.instance()
override fun onCreate() {
super.onCreate()
injector.inject(kodein)
}
37
KODEIN
53. ОСНОВНЫЕ ПРИНЦИПЫ
val scope = Toothpick.openScopes(app, this)
scope.installModules(ActivityModule(this))
Toothpick.inject(this, scope)
39
TOOTHPICK
54. ОСНОВНЫЕ ПРИНЦИПЫ
val scope = Toothpick.openScopes(app, this)
scope.installModules(ActivityModule(this))
Toothpick.inject(this, scope)
40
TOOTHPICK
55. ОСНОВНЫЕ ПРИНЦИПЫ
val scope = Toothpick.openScopes(app, this)
scope.installModules(ActivityModule(this))
Toothpick.inject(this, scope)
41
TOOTHPICK
56. ОСНОВНЫЕ ПРИНЦИПЫ
val scope = Toothpick.openScopes(app, this)
scope.installModules(ActivityModule(this))
Toothpick.inject(this, scope)
42
TOOTHPICK
63. ДЕКЛАРАЦИЯ ЗАВИСИМОСТЕЙ 45
@Module
class MainModule(val app: Application) {
@Provides
@Singleton
@Named(Tag.APPLICATION_CONTEXT)
private fun context(): Context = app
@Provides
private fun presenter(repo: Repository): Presenter
= PresenterImpl(repo)
}
LIGHTSABER
64. ДЕКЛАРАЦИЯ ЗАВИСИМОСТЕЙ
@Module
class MainModule(val app: Application) {
@Provides
@Singleton
@Named(Tag.APPLICATION_CONTEXT)
private fun context(): Context = app
@Provides
private fun presenter(repo: Repository): Presenter
= PresenterImpl(repo)
}
46
LIGHTSABER
65. ДЕКЛАРАЦИЯ ЗАВИСИМОСТЕЙ
@Module
class MainModule(val app: Application) {
@Provides
@Singleton
@Named(Tag.APPLICATION_CONTEXT)
private fun context(): Context = app
@Provides
private fun presenter(repo: Repository): Presenter
= PresenterImpl(repo)
}
47
LIGHTSABER
66. ДЕКЛАРАЦИЯ ЗАВИСИМОСТЕЙ
@Module
class MainModule(val app: Application) {
@Provides
@Singleton
@Named(Tag.APPLICATION_CONTEXT)
private fun context(): Context = app
@Provides
private fun presenter(repo: Repository): Presenter
= PresenterImpl(repo)
}
48
LIGHTSABER
88. ▸ Provider
▸ Factory
ДЕКЛАРАЦИЯ ЗАВИСИМОСТЕЙ
bind<RandomUtil>() with factory { num: Int ->
FakeRandom(num)
}
bind<RandomUtil>() with provider {
FakeRandom(2)
}
60
KODEIN
89. ▸ Provider
▸ Factory
ДЕКЛАРАЦИЯ ЗАВИСИМОСТЕЙ
bind<RandomUtil>() with factory { num: Int ->
FakeRandom(num)
}
bind<RandomUtil>() with provider {
FakeRandom(2)
}
60
KODEIN
90. ▸ Provider
▸ And many others
▸ Factory
ДЕКЛАРАЦИЯ ЗАВИСИМОСТЕЙ
bind<RandomUtil>() with factory { num: Int ->
FakeRandom(num)
}
bind<RandomUtil>() with provider {
FakeRandom(2)
}
60
KODEIN
95. ДЕКЛАРАЦИЯ ЗАВИСИМОСТЕЙ
class Module(val app: Application) : Module() {
init {
bind(Context ::class.java)
.withName(Tag.APP_CONTEXT)
.toInstance(app)
bind(Repository ::class.java)
.to(RepositoryImpl ::class.java)
.singletonInScope()
}
}
62
TOOTHPICK
96. ДЕКЛАРАЦИЯ ЗАВИСИМОСТЕЙ
class Module(val app: Application) : Module() {
init {
bind(Context ::class.java)
.withName(Tag.APP_CONTEXT)
.toInstance(app)
bind(Repository ::class.java)
.to(RepositoryImpl ::class.java)
.singletonInScope()
}
}
63
TOOTHPICK
97. ДЕКЛАРАЦИЯ ЗАВИСИМОСТЕЙ
class Module(val app: Application) : Module() {
init {
bind(Context ::class.java)
.withName(Tag.APP_CONTEXT)
.toInstance(app)
bind(Repository ::class.java)
.to(RepositoryImpl ::class.java)
.singletonInScope()
}
}
64
TOOTHPICK
98. ДЕКЛАРАЦИЯ ЗАВИСИМОСТЕЙ
class Module(val app: Application) : Module() {
init {
bind(Context ::class.java)
.withName(Tag.APP_CONTEXT)
.toInstance(app)
bind(Repository ::class.java)
.to(RepositoryImpl ::class.java)
.singletonInScope()
}
}
65
TOOTHPICK
99. class Module(val app: Application) : Module() {
init {
bind(Context ::class.java)
.withName(Tag.APP_CONTEXT)
.toInstance(app)
bind(Repository ::class.java)
.to(RepositoryImpl ::class.java)
.singletonInScope()
}
}
ДЕКЛАРАЦИЯ ЗАВИСИМОСТЕЙ 66
TOOTHPICK
118. SCOPES
val scope = Toothpick.openScope(this)
scope.installModules(AppModule(this))
Toothpick.inject(this, scope)
Toothpick.closeScope(this)
Место, где выполняются
инъекции
SCOPE
74
TOOTHPICK
119. SCOPES
val scope = Toothpick.openScope(this)
scope.installModules(AppModule(this))
Toothpick.inject(this, scope)
Toothpick.closeScope(this)
Место, где выполняются
инъекции
SCOPE
74
TOOTHPICK
120. val scope = Toothpick.openScope(this)
scope.installModules(AppModule(this))
Toothpick.inject(this, scope)
Toothpick.closeScope(this)
SCOPES
Место, где выполняются
инъекции
SCOPE
75
TOOTHPICK
130. SCOPES
▸ Аннотации по JSR 330
▸ Кастомные аннотации
@javax.inject.Scope
@Documented
@Retention(AnnotationRetention.RUNTIME)
annotation class PresenterScope
80
TOOTHPICK
131. SCOPES
▸ Аннотации по JSR 330
▸ Кастомные аннотации
val scope = Toothpick.openScopes(
application,
PresenterScope ::class.java,
this)
@javax.inject.Scope
@Documented
@Retention(AnnotationRetention.RUNTIME)
annotation class PresenterScope
80
TOOTHPICK
132. SCOPES
▸ Аннотации по JSR 330
▸ Кастомные аннотации
val scope = Toothpick.openScopes(
application,
PresenterScope ::class.java,
this)
@javax.inject.Scope
@Documented
@Retention(AnnotationRetention.RUNTIME)
annotation class PresenterScope
80
TOOTHPICK
137. ТЕСТИРОВАНИЕ
▸ Нужно просто переопределять
все необходимые модули в
тестах
@Module
class Module {
@Provides
private fun presenter(): MainPresenter
= FakePresenter()
}
82
LIGHTSABER
141. ТЕСТИРОВАНИЕ
class TestApp : App() {
override val kodein: Kodein by lazy {
Kodein {
import(
module = appModule(this@TestApp),
allowOverride = true
)
constant("TEST", overrides = true) with 4L
}
}
}
▸ Флаг allowOverride = true
83
KODEIN
142. ТЕСТИРОВАНИЕ
class TestApp : App() {
override val kodein: Kodein by lazy {
Kodein {
import(
module = appModule(this@TestApp),
allowOverride = true
)
constant("TEST", overrides = true) with 4L
}
}
}
▸ Флаг allowOverride = true
83
KODEIN
158. ЕСТЬ ЛИ ЖИЗНЬ БЕЗ DAGGER’A?
KODEIN.CONCLUSION()
▸Действительно лёгкий
87
159. ЕСТЬ ЛИ ЖИЗНЬ БЕЗ DAGGER’A?
KODEIN.CONCLUSION()
▸Действительно лёгкий
▸Kotlin friendly
87
160. ЕСТЬ ЛИ ЖИЗНЬ БЕЗ DAGGER’A?
KODEIN.CONCLUSION()
▸Действительно лёгкий
▸Kotlin friendly
▸Runtime-проверка графа
87
161. ЕСТЬ ЛИ ЖИЗНЬ БЕЗ DAGGER’A?
KODEIN.CONCLUSION()
▸Действительно лёгкий
▸Kotlin friendly
▸Runtime-проверка графа
▸С тестированием уже
легче
87
167. TOOTHPICK.CONCLUSION()
ЕСТЬ ЛИ ЖИЗНЬ БЕЗ DAGGER’A?
▸Детальный Scope
▸Бро для тестов
▸Compile + Runtime-проверка
графа
▸Нельзя сказать, что они достигли
простоты по сравнению с Dagger
88
168. ЕСТЬ ЛИ ЖИЗНЬ БЕЗ DAGGER’A?
FINAL
89
Simplicity Scope Tests Perf
Lightsaber
Kodein
Toothpick
Dagger
169. СПАСИБО!
OMG! NOW I NEED A
KODEIN DOZE..
special thanks to @georgeci
Ligthsaber
Kodein
Tootpick
git.io/v7cw8
git.io/v7cwY
git.io/v7cwg