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
Sato Shun
September 10, 2019
Programming
2
2.3k
タップルでたっぷりDaggerを使って マルチモジュール構築している話 :)
タップルでたっぷりDaggerを使ってマルチモジュール構築している話です!
Sato Shun
September 10, 2019
Tweet
Share
More Decks by Sato Shun
See All by Sato Shun
Kotlin Nativeにおけるfrozen状態と並行処理について
satoshun
0
800
DroidKaigi 2020: System UIをコントロールして、 画面を最大限に生かしたアプリを構築する / Build apps that make the best uses of device screens by controlling System UI
satoshun
4
1.7k
Kotlin Fest 2019: Kotlin型実践入門
satoshun
9
6.1k
R8/ProGuard 徹底比較
satoshun
8
3.8k
Android: Introduction Android Support Annotations
satoshun
0
94
Android: Daggear2でDI
satoshun
0
97
Other Decks in Programming
See All in Programming
Rustのweb開発を助ける 便利なツール紹介
yuki0418
1
190
ぼっちを避けて楽しむためのアノテコノテ / Various Tips and Tricks to Avoid Loneliness and Have Fun
nrslib
3
1.7k
12年前の『型システム入門』翻訳の思い出話
mame
11
1.2k
日付と正規化
megmogmog1965
0
140
Play Billing Library 7.0.0 変更点まとめ@potatotips#88
kako351
0
160
企業向け生成AIアプリの 開発から得られた知見
takaakikakei
0
310
Namespace on read
tagomoris
2
370
スクラムマスターって孤独じゃないですか?
yoshitaroyoyo
1
140
【Go言語】golangci-lintの使い方
tomo1227
0
270
AHC035解説
terryu16
0
710
君たちはどうコードをレビューする (される) か / 大吉祥寺.pm
utgwkk
15
8.5k
開発部に不満を持っていたCSがエンジニアにジョブチェンしてわかった「勝手に諦めない」ことの大切さ
sakuraikotone
28
16k
Featured
See All Featured
Typedesign – Prime Four
hannesfritz
37
2.2k
VelocityConf: Rendering Performance Case Studies
addyosmani
321
23k
How GitHub (no longer) Works
holman
305
140k
Leading Effective Engineering Teams 2024
addyosmani
3
300
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
12
3.8k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
26
1.6k
Imperfection Machines: The Place of Print at Facebook
scottboms
262
13k
How To Stay Up To Date on Web Technology
chriscoyier
784
250k
Product Roadmaps are Hard
iamctodd
PRO
48
10k
Six Lessons from altMBA
skipperchong
24
3.2k
ParisWeb 2013: Learning to Love: Crash Course in Emotional UX Design
dotmariusz
105
6.8k
Bash Introduction
62gerente
607
210k
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ϞδϡʔϧͰߦ͍ͬͯΔ