Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
タップルでたっぷりDaggerを使って マルチモジュール構築している話 :)
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Sato Shun
September 10, 2019
Programming
2.6k
2
Share
タップルでたっぷりDaggerを使って マルチモジュール構築している話 :)
タップルでたっぷりDaggerを使ってマルチモジュール構築している話です!
Sato Shun
September 10, 2019
More Decks by Sato Shun
See All by Sato Shun
Kotlin Nativeにおけるfrozen状態と並行処理について
satoshun
0
1k
DroidKaigi 2020: System UIをコントロールして、 画面を最大限に生かしたアプリを構築する / Build apps that make the best uses of device screens by controlling System UI
satoshun
4
1.9k
Kotlin Fest 2019: Kotlin型実践入門
satoshun
9
7k
R8/ProGuard 徹底比較
satoshun
8
4.3k
Android: Introduction Android Support Annotations
satoshun
0
150
Android: Daggear2でDI
satoshun
0
180
Other Decks in Programming
See All in Programming
なぜあなたのコードには「コシ」がないのか?〜AI時代に問う、最後まで美味しい設計と戦略〜 #phpconkagawa / phpconkagawa2026
shogogg
0
100
Swift Concurrency Type System
inamiy
1
570
Spec-driven Development: How AI Changes Everything (And Nothing)
simas
PRO
0
570
tRPCの概要と少しだけパフォーマンス
misoton665
2
250
PCOVから学ぶコードカバレッジ #phpcon_odawara
o0h
PRO
0
290
How Swift's Type System Guides AI Agents
koher
0
320
実践CRDT
tamadeveloper
0
610
PHPer、Cloudflare に引っ越す
suguruooki
1
130
PHPでローカル環境用のSSL/TLS証明書を発行することはできるのか? #phpconkagawa
akase244
0
290
Oxlintとeslint-plugin-react-hooks 明日から始められそう?
t6adev
0
310
PHPでバイナリをパースして理解するASN.1
muno92
PRO
0
360
Firefoxにコントリビューションして得られた学び
ken7253
2
150
Featured
See All Featured
We Are The Robots
honzajavorek
0
220
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
230
The Illustrated Children's Guide to Kubernetes
chrisshort
51
52k
Darren the Foodie - Storyboard
khoart
PRO
3
3.3k
Speed Design
sergeychernyshev
33
1.6k
Docker and Python
trallard
47
3.8k
How Software Deployment tools have changed in the past 20 years
geshan
0
33k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.2k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
1.9k
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
2k
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
Transcript
CA.apk #8 ࠤ౻ ൏ / Sato Shun Twitter: @stsn_jp GitHub:
satoshun λοϓϧͰͨͬΓDaggerΛͬͯ ϚϧνϞδϡʔϧߏங͍ͯ͠Δ :)
ँࣙ • λΠτϧɺogaclejapan͞ΜͷɺFlux de Relax :) Λࢀ ߟʹ͓ͯ͠Γ·͢ • https://speakerdeck.com/ogaclejapan/flux-de-relax
ࠓճ͞ͳ͍͜ͱ • DaggerૉΒ͍͠Μͩͧʂ͍ͬͯ͏Ͱͳ͍Ͱ͢ • Koinͱ͔ଞͷϥΠϒϥϦͳͲͷൺֱͰ͋Γ·ͤΜ
ࠓճ͢͜ͱ • Daggerͷجຊߏ • ϚϧνϞδϡʔϧͷجຊߏ • AnalyticsϞδϡʔϧΛྫʹɺϥΠϒϥϦͷࣝΛϞ δϡʔϧʹด͡ࠐΊΔํ๏ • ֤FeatureϞδϡʔϧͷ
• RouterϞδϡʔϧͷ
Daggerͷجຊߏ • Android Daggerͬͯ·͢ • ͨͩɺແཧͯ͠͏ඞཁͳ͍ͱࢥ͏:D • Dynamic Feature Moduleͱ૬ੑѱ͍ʢଟʣ
• ViewModelͷαϙʔτ͕ೖͬͨΒϫϯͪΌΜ (ISSUE͋Δ) • શ෦ɺDagger͔ΒΠϯελϯε࡞Ζ͏ͥʙͬͯײ͡Ͱͳ ͍ • ࣮DaggerΛͨͬΓͬͯͳ͍Ͱ͢
None
None
None
None
None
@Singleton @Component( modules = [ AndroidInjectionModule::class, FeatureModule::class, AnalyticsModule::class ] )
interface AppComponent : AndroidInjector<App> { ... }
@Singleton @Component( modules = [ AndroidInjectionModule::class, FeatureModule::class, AnalyticsModule::class ] )
interface AppComponent : AndroidInjector<App> { ... }
AnalyticsModule? • AnalyticsϞδϡʔϧʹఆٛ͞Ε͍ͯΔDaggerͷModule • Google Analytics for Firebaseʹґଘ͍ͯ͠Δ • Google
AnalyticsͱͬͬͬͯͰ͔͍ϥΠϒϥϦ • Google AnalyticsͷҰ෦ͷػೳ͔͍ͬͯ͠ͳ͍͠ɺ্ख͍͜ ͱΓ͍ͨ
interface Analytics { ... } .
interface Analytics { ... } . @Singleton internal class FirebaseAnalyticsImpl
@Inject constructor( private val app: Application ) : Analytics { ... } .
interface Analytics { ... } . @Singleton internal class FirebaseAnalyticsImpl
@Inject constructor( private val app: Application ) : Analytics { ... } .
interface Analytics { . ... } . @Singleton internal class
FirebaseAnalyticsImpl @Inject constructor( . private val app: Application ) : Analytics { . ... } .
interface Analytics { . ... . } . @Singleton internal
class FirebaseAnalyticsImpl @Inject constructor( . private val app: Application ) : Analytics { . ... . } . @Module internal interface AnalyticsBindModule { . @Binds fun bind(impl: FirebaseAnalyticsImpl): Analytics } .
interface Analytics { . ... . } . @Singleton internal
class FirebaseAnalyticsImpl @Inject constructor( . private val app: Application ) : Analytics { . ... . } . @Module internal interface AnalyticsBindModule { . @Binds fun bind(impl: FirebaseAnalyticsImpl): Analytics } .
interface Analytics { . ... . } . @Singleton .
internal class FirebaseAnalyticsImpl @Inject constructor( . private val app: Application ) : Analytics { . ... . } . @Module . internal interface AnalyticsBindModule { .. @Binds fun bind(impl: FirebaseAnalyticsImpl): Analytics } ..
@Singleton internal class FirebaseAnalyticsImpl @Inject constructor( . private val app:
Application ) : Analytics { ... . } . @Module . internal interface AnalyticsBindModule { .. @Binds fun bind(impl: FirebaseAnalyticsImpl): Analytics } .. . @Module(includes = [AnalyticsBindModule::class]) .. object AnalyticsModule { .. ... } .
@Singleton @Component( modules = [ AndroidInjectionModule::class, FeatureModule::class, AnalyticsModule::class ] )
interface AppComponent : AndroidInjector<App> { ... }
internal class GachaFragment : Fragment() { @Inject lateinit var analytics:
FirebaseAnalyticsImpl ... } .
internal class GachaFragment : Fragment() { @Inject lateinit var analytics:
Analytics ... } .
AnalyticsModule·ͱΊ • αʔυύʔςΟϥΠϒϥϦ͕ڊେ͔ͭɺͦͷࣝΛग़དྷ ΔݶΓด͡ࠐΊ͍ͨͱ͖ʹ༗ޮͳख๏ • ઐ༻ͷϞδϡʔϧΛ࡞ͬͯ͋͛ͯɺΠϯλϑΣʔεΛఆ ٛɻͦͯ͠ɺ࣮Λinternalɺ@BindsͰґଘΛఆٛ͢Δ • ·ͨϝϯς͞Ε͍ͯͳ͍ɺAPI͕ෳࡶͳࣾϥΠϒϥϦ ʹ༗ޮʹ͏͜ͱ͕ग़དྷΔ
• ϝϯς͞Εͯͳ͍ࣾϥΠϒϥϦͳΜͯͳ͍ΜͩΑͳ͊
֤FeatureϞδϡʔϧʹ͍ͭͯ • ֤FeatureϞδϡʔϧ͝ͱʹઐ༻ͷDaggerͷModuleΛ ͍࣋ͬͯΔ • gachaϞδϡʔϧ: GachaFeatureModule • settingϞδϡʔϧ: SettingFeatureModule
• …
@Module interface GachaFeatureModule { @ContributesAndroidInjector fun contributeGachaActivity(): GachaActivity }
@Module interface GachaFeatureModule { @ContributesAndroidInjector fun contributeGachaActivity(): GachaActivity } @Module(
includes = [ GachaFeatureModule::class, ] ) interface FeatureModule
@Module interface GachaFeatureModule { @ContributesAndroidInjector fun contributeGachaActivity(): GachaActivity } @Module(
includes = [ GachaFeatureModule::class, SettingFeatureModule::class, ] ) interface FeatureModule
@Module interface GachaFeatureModule { @ContributesAndroidInjector fun contributeGachaActivity(): GachaActivity } @Module(
includes = [ GachaFeatureModule::class, SettingFeatureModule::class, ShopFeatureModule::class, . ] ) interface FeatureModule
GachaFeatureModule::class, . SettingFeatureModule::class, . ShopFeatureModule::class, . ] . ) .
interface FeatureModule . @Singleton @Component( modules = [ AndroidInjectionModule::class, FeatureModule::class, AnalyticsModule::class ] ) interface AppComponent : AndroidInjector<App> { ... }
GachaFeatureModule::class, . SettingFeatureModule::class, . ShopFeatureModule::class, . ] . ) .
interface FeatureModule . @Singleton @Component( modules = [ AndroidInjectionModule::class, FeatureModule::class, AnalyticsModule::class ] ) interface AppComponent : AndroidInjector<App> { ... }
FeatureϞδϡʔϧ·ͱΊ • FeatureϞδϡʔϧຖʹɺSettingFeatureModuleΈ͍ͨ ͳײ͡ͰModuleΛఆٛ͢Δ • ଞͷΫϥεinternalͰఆٛ͢Δ͜ͱͰɺ֎ͷϞδϡʔϧ͔ ΒͷࢀরΛ࠷খݶʹ͢Δ͜ͱ͕ग़དྷΔ • ϞδϡʔϧؒͷґଘΛݮΒ͢͜ͱ͕ग़དྷΔʂ
FeatureϞδϡʔϧؒͷભҠʹ͍ͭͯ • ֤ը໘ʢFeatureʣΛαϒϞδϡʔϧʹΓग़ͨ͜͠ͱ Ͱɺ͓ޓ͍͕ࢀরग़དྷͳ͘ͳΔ • େ͖͘3ͭͷํ๏͕͋Δʢଟʣ
FeatureϞδϡʔϧؒͷભҠʹ͍ͭͯ 1 • จࣈྻʢϦϑϨΫγϣϯʣͰࢦఆ͢Δํ๏ • PlaidͰΘΕͯΔํ๏
object Activities { /** * AboutActivity */ object About :
AddressableActivity { override val className = "$PACKAGE_NAME.about.ui.AboutA ctivity" } }
FeatureϞδϡʔϧؒͷભҠʹ͍ͭͯ 2 • ֤FeatureϞδϡʔϧʹભҠ༻ͷΠϯλʔϑΣʔεΛ ఆٛͯ͠ɺappϞδϡʔϧͰ࣮͢Δ • Navigation Componentͱͷ૬ੑྑ͍ʂʂ
FeatureϞδϡʔϧؒͷભҠʹ͍ͭͯ 2 • ֤FeatureϞδϡʔϧʹભҠ༻ͷΠϯλʔϑΣʔεΛ ఆٛͯ͠ɺappϞδϡʔϧͰ࣮͢Δ • Navigation Componentͱͷ૬ੑྑ͍ʂʂ
FeatureϞδϡʔϧؒͷભҠʹ͍ͭͯ 3 • ઐ༻ͷϞδϡʔϧΛ࡞ͯ͠ɺ֤ը໘༻ͷΠϯλʔ ϑΣʔεΛఆٛ͢Δ • λοϓϧͰͦͷઐ༻ϞδϡʔϧΛRouterͰ࡞͍ͯ͠Δ • interface GachaDirections
• interface SettingDirections • ֤FeatureϞδϡʔϧͰɺ͜ͷDirectionsΠϯλʔϑΣʔ εΛ͍ભҠ͢Δ
// ͜ΕRouterϞδϡʔϧͰఆٛ interface GachaDirections { .. @CheckResult fun createIntent(context: Context):
Intent } .
// ͜ΕRouterϞδϡʔϧͰఆٛ interface GachaDirections { .. @CheckResult fun createIntent(context: Context):
Intent } . // ҎԼɺGachaϞδϡʔϧ internal class GachaDirectionsImpl @Inject constructor() : GachaDirections { . override fun createIntent(context: Context): Intent { . return GachaActivity.createIntent(context) } . } .
} . // ҎԼɺGachaϞδϡʔϧ internal class GachaDirectionsImpl @Inject constructor() :
GachaDirections { . override fun createIntent(context: Context): Intent { . return GachaActivity.createIntent(context) } . } . @Module internal interface GachaBindsModule { . @Binds fun bindGachaDirections(directions: GachaDirectionsImpl): GachaDirections } .
override fun createIntent(context: Context): Intent { . return GachaActivity.createIntent(context) }
. } . @Module internal interface GachaBindsModule { . @Binds fun bindGachaDirections(directions: GachaDirectionsImpl): GachaDirections } . @Module( includes = [ GachaBindsModule::class ] ) interface GachaFeatureModule
@Singleton @Component( modules = [ AndroidInjectionModule::class, FeatureModule::class, AnalyticsModule::class, ] )
interface AppComponent : AndroidInjector<App> { ... }
@Module( includes = [ GachaFeatureModule::class, ... ] ) interface FeatureModule
class MainActivity : AppCompatActivity() { @Inject lateinit var gachaDirections: GachaDirections
}
None
·ͱΊ • Google AnalyticsͳͲͷϥΠϒϥϦͷࣝΛด͡ࠐΊΔͨΊ ʹɺϞδϡʔϧΛఆٛ͠ɺDaggerͰґଘΛղܾ͢Δ • ϥΠϒϥϦ͕มΘΔՄೳੑ͕ߴ͍߹ɺΑΓ༗ޮ • ֤ը໘ͷભҠɺΠϯλʔϑΣʔεΛదͳϞδϡʔϧʹ ஔͯ͠ɺదͳϞδϡʔϧͰ࣮͠ɺDaggerͰґଘΛղܾ͢Δ
• λοϓϧͩͱRouterϞδϡʔϧʹΠϯλʔϑΣʔεΛஔɺ࣮ ֤FeatureϞδϡʔϧͰߦ͍ͬͯΔ