Slide 1

Slide 1 text

,PUMJO.11Ͱ 6*ϩδοΫ·Ͱڞ௨Խͯ͠ ָΛ͍ͨ͠ ,PUMJOѪ޷ձ ʹ͜͠Γ͞ͿΖʙ!TVCSPI@

Slide 2

Slide 2 text

"CPVU.F ʹ͜͠Γ͞ͿΖʙ ✦౦ژ౎ɾҏ౾େౡग़਎ ✦גࣜձࣾ#&"35"*- ‣ "OESPJEΤϯδχΞ ,PUMJO+BWB ˑ ‣ 8FCΤϯδχΞ 3BJMT3FBDU

Slide 3

Slide 3 text

͸͡Ίʹʜ ,PUMJO.VMUJQMBUGPSN ۀ຿PSझຯͰ৮͍ͬͯΔਓʔʂ🙌

Slide 4

Slide 4 text

͸͡Ίʹʜ 㾎͜͜࠷ۙ੝Γ্͕Γͭͭ͋Δ,PUMJO.VMUJQMBUGPSN ೥݄ɺ,PUMJO.VMUJQMBUGPSN.PCJMFͷЋ൛ϦϦʔε ϞόΠϧ޲͚ϓϩδΣΫτͷ਽ܗΛࣗಈੜ੒ ຊ൪؀ڥͰͷ࠾༻ࣄྫ /FUqJY 8BOUFEMZ ΤϜεϦʔ OFUqJYUFDICMPHDPNOFUqJYBOESPJEBOEJPTTUVEJPBQQTLPUMJONVMUJQMBUGPSNEEEEE XXXXBOUFEMZDPNDPNQBOJFTXBOUFEMZQPTU@BSUJDMFT XXXNUFDICMPHFOUSZ ৿ཏສ৅Λ,PUMJOͰ࣮૷Ͱ͖Δੈք ਱ʹݱ࣮ʹͳΔͷ͔ʜʂʁ

Slide 5

Slide 5 text

͸͡ΊͷҰาΛ્Ή৺ͷ੠ 㾎͜͜࠷ۙ੝Γ্͕Γͭͭ͋Δ,PUMJO.VMUJQMBUGPSN ೥݄ɺ,PUMJO.VMUJQMBUGPSN.PCJMFͷЋ൛ϦϦʔε ϞόΠϧ޲͚ϓϩδΣΫτͷ਽ܗΛࣗಈੜ੒ ຊ൪؀ڥͰͷ࠾༻ࣄྫ /FUqJY 8BOUFEMZ ΤϜεϦʔ OFUqJYUFDICMPHDPNOFUqJYBOESPJEBOEJPTTUVEJPBQQTLPUMJONVMUJQMBUGPSNEEEEE XXXXBOUFEMZDPNDPNQBOJFTXBOUFEMZQPTU@BSUJDMFT XXXNUFDICMPHFOUSZ ৿ཏສ৅Λ,PUMJOͰ࣮૷Ͱ͖Δੈք ਱ʹݱ࣮ʹͳΔͷ͔ʜʂʁ ͍͘ΒϩδοΫΛڞ௨ԽͰ͖ͯ΋ ϏϧυεΫϦϓτ͕ࠇຐज़ͩͬͨΒҙຯͳ͍Μ͡Ό🥺 ,PUMJOΊͬͪΌΘ͔Δ ໠ऀ͡Όͳ͍ͱ࢖͍͜ͳͤͳ͍ͷͰ͸🥺 ˞ڞ௨ԽͰָΛ͢Δ ௒͑ΒΕͳ͍น ϏϧυͷͭΒΈ ɹ91MBUͰ͋Γ͕ͪͳ᠘

Slide 6

Slide 6 text

࿩͢͜ͱ ˑ,PUMJO.11ͰΞϓϦΛαΫͬͱ࡞ͬͯײͨ͜͡ͱ 㾎Ϟμϯͳߏ੒ͷΞϓϦΛͲͷఔ౓ͷ࿑ྗͰ࣮૷Ͱ͖Δ͔ 㾎6*ϩδοΫ·Ͱڞ௨Խͯ͠ྑ͔ͬͨ͜ͱɺͭΒ͔ͬͨ͜ͱ 㾎ࠓޙͷల๬

Slide 7

Slide 7 text

,PUMJO.11ͷҒେͳઌߦࣄྫ 㾎%SPJE,BJHJެࣜΞϓϦ 💪೔ຊޠݍͷ։ൃऀ͕࠷΋ΞΫηε͠΍͘͢ɺ͔ͭ৘ใྔͷଟ͍ΞϓϦ 💪$PSPVUJOFTʹΑΔඇಉظॲཧϚϧνϞδϡʔϧ%*CZ%BHHFS ͔͠͠J04ଆͰ͸ʜ 🥺TVTQFOE͕࢖͑ͳ͍ˠίʔϧόοΫͰϒϦοδ 🥺ෳ਺ϞδϡʔϧͷࢀরʹIBDL͕ඞཁ (JU)VC%SPJE,BJHJDPOGFSFODFBQQ ·ͩ·ͩػೳෆ଍ͩͬͨ,PUMJOͰ ΊͪΌͪ͘Όؤு͍ͬͯΔ௒ҒେͳΞϓϦ

Slide 8

Slide 8 text

,PUMJOͱ,..ͷొ৔ 㾎,PUMJOͷ.11త໨ۄ 🎉,PUMJO/BUJWFͰͷTVTQFOEؔ਺ͷαϙʔτ 🎉.11޲͚ͷެࣜυΩϡϝϯτ͕΍ͨΒ૿͑ͨ 㾎,..ͷొ৔ 🥰΢ΟβʔυܗࣜͰ"OESPJEJ04྆ରԠͷ)FMMP 8PSME͕࡞ΕΔʂ 🥰ϛχϚϜͳJ04޲͚ͷϏϧυεΫϦϓτ͕࠷ॳ͔Β༻ҙ͞Ε͍ͯΔʂ ࣌఺ ࣌఺ ,PUMJOͰͷػೳ௥Ճ,..Ͱͷॳಈαϙʔτ ܥͷ࣌୅͔Β࣮֬ʹ৮Γ΍͘͢ͳ͍ͬͯΔʂ

Slide 9

Slide 9 text

࣮ࡍʹ࡞ͬͨϞϊ 㾎ΞΠυϧϚελʔʹొ৔͢ΔΞΠυϧΛݕࡧ͢ΔΞϓϦ $PSPVUJOFTʹΑΔඇಉظॲཧϚϧνϞδϡʔϧ 6*ϩδοΫ 7JFX.PEFM ·Ͱڞ௨Խ %*༻ίʔυ΋΄΅ڞ௨Խ

Slide 10

Slide 10 text

࣮૷ղઆ 㾎$PSPVUJOFTʹΑΔඇಉظॲཧ LPUMJOYDPSPVUJOFT͕.11ʹରԠ ϚϧνεϨουରԠͷBSUJGBDUΛར༻ γϯϓϧͳ֎෦"1*ͱͷ΍ΓऔΓͳΒ໰୊ͳ͘ಈ࡞ ͜Ε ˞4UBCMF൛ͱͷࠩ͸ׂͱ͋ΔͷͰෳࡶͳ͜ͱΛ ͢Δͱ૝ఆ֎ͷڍಈʹͳΔ͔΋ʜ

Slide 11

Slide 11 text

࣮૷ղઆ 㾎ϚϧνϞδϡʔϧ ԼهͷΑ͏ͳϞδϡʔϧߏ੒ͷ৔߹ BQJˠ)UUQ$MJFOUͷఆٛ DPNQPOFOUTˠ%*ؔ࿈ͷϝιουɾΫϥε J04޲͚BSUJGBDUੜ੒ EBUBJOGSBˠϨϙδτϦͷఆٛ EBUBNPEFMˠΤϯςΟςΟɾ஋ΦϒδΣΫτͷఆٛ QSFTFOUBUJPOˠ6*ϩδοΫͷఆٛ

Slide 12

Slide 12 text

࣮૷ղઆ 㾎ϚϧνϞδϡʔϧ kotlin { android() ios { binaries { framework { baseName = "shared" } } } sourceSets { val commonMain by getting { dependencies { implementation(project(":shared:data:model")) implementation(project(":shared:presentation")) implementation(project(":shared:api")) implementation(project(":shared:data:infra")) ... } DPNQPOFOUTCVJMEHSBEMFLUT ,..Ͱ࡞੒ͨ͠ ॳظͷঢ়ଶ͔Βʜ

Slide 13

Slide 13 text

࣮૷ղઆ 㾎ϚϧνϞδϡʔϧ kotlin { android() ios { binaries { framework { baseName = "shared" export(project(":shared:data:model")) export(project(":shared:presentation")) } } } sourceSets { val commonMain by getting { dependencies { api(project(":shared:data:model")) api(project(":shared:presentation")) implementation(project(":shared:api")) implementation(project(":shared:data:infra")) ... } J04޲͚ʹެ։͍ͨ͠ ϞδϡʔϧΛFYQPSU DPNNPO.BJO಺ͷґଘؔ܎Λ JNQMFNFOUBUJPOˠBQJʹमਖ਼ DPNQPOFOUTCVJMEHSBEMFLUT ˒EBUBNPEFMͱQSFTFOUBUJPO಺ͷ Ϋϥεɾϝιου͕J04͔ΒࢀরՄೳʹʂ

Slide 14

Slide 14 text

࣮૷ղઆ 㾎ϚϧνϞδϡʔϧ ҼΈʹܥͷ࣌୅ͷ ϚϧνϞδϡʔϧରԠ͸ʜ SFGRJJUBDPNUBLBIJSPNJUFNTEGCGDBBF ͱͯ΋ͭΒ͍🥺 ˒ϚϧνϞδϡʔϧରԠ͸ܥ͔Β େ෯ʹָʹͳͬͨ🎉

Slide 15

Slide 15 text

࣮૷ղઆ 㾎6*ϩδοΫڞ௨Խ ""$ͷ7JFX.PEFMΛDPNNPO.BJOͰѻ͑ΔΑ͏ʹίʔυΛ௥Ճ expect abstract class ViewModel constructor( coroutineScope: CoroutineScope? = null, ) { val viewModelScope: CoroutineScope } DPNNPO.BJO7JFX.PEFMLU import androidx.lifecycle.ViewModel as AndroidViewModel import androidx.lifecycle.viewModelScope as androidViewModelScope actual abstract class ViewModel actual constructor( coroutineScope: CoroutineScope? ) : AndroidViewModel() { actual val viewModelScope = coroutineScope ?: androidViewModelScope } BOESPJE.BJO"OESPJE7JFX.PEFMLU actual abstract class ViewModel actual constructor( coroutineScope: CoroutineScope? ) { actual val viewModelScope = coroutineScope ?: MainScope() } JPT.BJO/BUJWF7JFX.PEFMLU

Slide 16

Slide 16 text

࣮૷ղઆ 㾎6*ϩδοΫڞ௨Խ ""$ͷ7JFX.PEFMΛDPNNPO.BJOͰѻ͑ΔΑ͏ʹίʔυΛ௥Ճ expect abstract class ViewModel constructor( coroutineScope: CoroutineScope? = null, ) { val viewModelScope: CoroutineScope } DPNNPO.BJO7JFX.PEFMLU import androidx.lifecycle.ViewModel as AndroidViewModel import androidx.lifecycle.viewModelScope as androidViewModelScope actual abstract class ViewModel actual constructor( coroutineScope: CoroutineScope? ) : AndroidViewModel() { actual val viewModelScope = coroutineScope ?: androidViewModelScope } BOESPJE.BJO"OESPJE7JFX.PEFMLU actual abstract class ViewModel actual constructor( coroutineScope: CoroutineScope? ) { actual val viewModelScope = coroutineScope ?: MainScope() } JPT.BJO/BUJWF7JFX.PEFMLU DPNNPO.BJOʹ FYQFDUम০ࢠΛ͚ͭͯ 7JFX.PEFMΛఆٛ

Slide 17

Slide 17 text

࣮૷ղઆ 㾎6*ϩδοΫڞ௨Խ ""$ͷ7JFX.PEFMΛDPNNPO.BJOͰѻ͑ΔΑ͏ʹίʔυΛ௥Ճ expect abstract class ViewModel constructor( coroutineScope: CoroutineScope? = null, ) { val viewModelScope: CoroutineScope } DPNNPO.BJO7JFX.PEFMLU import androidx.lifecycle.ViewModel as AndroidViewModel import androidx.lifecycle.viewModelScope as androidViewModelScope actual abstract class ViewModel actual constructor( coroutineScope: CoroutineScope? ) : AndroidViewModel() { actual val viewModelScope = coroutineScope ?: androidViewModelScope } BOESPJE.BJO"OESPJE7JFX.PEFMLU actual abstract class ViewModel actual constructor( coroutineScope: CoroutineScope? ) { actual val viewModelScope = coroutineScope ?: MainScope() } JPT.BJO/BUJWF7JFX.PEFMLU ""$ͷ7JFX.PEFMΛܧঝ WJFX.PEFM4DPQF΋ +FUQBDLͷ֦ுϓϩύςΟΛࢀর

Slide 18

Slide 18 text

࣮૷ղઆ 㾎6*ϩδοΫڞ௨Խ ""$ͷ7JFX.PEFMΛDPNNPO.BJOͰѻ͑ΔΑ͏ʹίʔυΛ௥Ճ expect abstract class ViewModel constructor( coroutineScope: CoroutineScope? = null, ) { val viewModelScope: CoroutineScope } DPNNPO.BJO7JFX.PEFMLU import androidx.lifecycle.ViewModel as AndroidViewModel import androidx.lifecycle.viewModelScope as androidViewModelScope actual abstract class ViewModel actual constructor( coroutineScope: CoroutineScope? ) : AndroidViewModel() { actual val viewModelScope = coroutineScope ?: androidViewModelScope } BOESPJE.BJO"OESPJE7JFX.PEFMLU actual abstract class ViewModel actual constructor( coroutineScope: CoroutineScope? ) { actual val viewModelScope = coroutineScope ?: MainScope() } JPT.BJO/BUJWF7JFX.PEFMLU J04ଆ͸Կ΋ܧঝ͠ͳ͍ WJFX.PEFM4DPQF͸ ͱΓ͋͑ͣ .BJO4DPQFΛ౉͢

Slide 19

Slide 19 text

࣮૷ղઆ 㾎6*ϩδοΫڞ௨Խ class IdolsViewModel( private val repository: IdolsRepository, ) : ViewModel() { private val idolsLoadState: MutableStateFlow = MutableStateFlow(LoadState.Initialize) private val queryState: MutableStateFlow = MutableStateFlow("") val uiModel: StateFlow get() = combine( idolsLoadState, queryState, ) { idolsLoadState, _ -> IdolsUiModel(idolsLoadState) }.distinctUntilChanged().stateIn(viewModelScope, SharingStarted.Eagerly, IdolsUiModel()) fun search(query: String? = null) { val job = viewModelScope.launch(start = CoroutineStart.LAZY) { runCatching { withContext(Dispatchers.Default) { repository.search(query) } } .onSuccess { idolsLoadState.value = LoadState.Loaded(it) } .onFailure { idolsLoadState.value = LoadState.Error(it) } } idolsLoadState.value = LoadState.Loading(job) job.start() } } ˒"OESPJEJ04ͷࠩΛҙࣝͤͣ ɹ6*ϩδοΫͷ࣮૷͕Մೳʹ🎉 ໊લݕࡧػೳΛ࣮૷ͨ͠ 7JFX.PEFM DPNNPO.BJO*EPMT7JFX.PEFMLU

Slide 20

Slide 20 text

࣮૷ղઆ 㾎%*ίʔυڞ௨Խ ,PEFJOͱ,PJO Ћ൛ ͕.11ʹରԠ ,PEFJOΛར༻͠ɺඞཁͳΠϯελϯεΛ஫ೖ "OESPJEͷ৔߹ class MainActivity : AppCompatActivity(), DIAware { override val di: DI = IdolsViewModelDI(Main.Module) private val viewModel: IdolsViewModel by viewModels { di.direct.instance() } ... .BJO"DUJWJUZLU

Slide 21

Slide 21 text

࣮૷ղઆ 㾎%*ίʔυڞ௨Խ ,PEFJOͱ,PJO Ћ൛ ͕.11ʹରԠ ,PEFJOΛར༻͠ɺඞཁͳΠϯελϯεΛ஫ೖ "OESPJEͷ৔߹ class MainActivity : AppCompatActivity(), DIAware { override val di: DI = IdolsViewModelDI(Main.Module) private val viewModel: IdolsViewModel by viewModels { di.direct.instance() } ... .BJO"DUJWJUZLU %*"XBSFΛܧঝ EJϓϩύςΟʹ ϞδϡʔϧΛ౉ͯ͠஫ೖ

Slide 22

Slide 22 text

࣮૷ղઆ 㾎%*ίʔυڞ௨Խ ,PEFJOΛར༻͠ɺඞཁͳΠϯελϯεΛ஫ೖ J04ͷ৔߹ fun createViewModel( di: DI, ): IdolsViewModel = di.direct.instance().create() JPT.BJO/BUJWF%*LU 4XJGUͷΫϥεʹ%*"XBSFΛ্ख͘ܧঝͤ͞ΒΕͳ͍🥺 ˠ%*Ϟδϡʔϧ͔ΒΠϯελϯεΛ௚઀ҾͬுΔϝιουΛ࣮૷

Slide 23

Slide 23 text

࣮૷ղઆ 㾎%*ίʔυڞ௨Խ ,PEFJOΛར༻͠ɺඞཁͳΠϯελϯεΛ஫ೖ J04ͷ৔߹ class MainViewController: UIViewController, UISearchBarDelegate { private let di = IdolsViewModelDIKt.IdolsViewModelDI(modules: [Main().Module]) override func viewDidLoad() { super.viewDidLoad() viewModel = NativeDIKt.createViewModel(di: di) } ... .BJO7JFX$POUSPMMFSTXJGU

Slide 24

Slide 24 text

࣮૷ղઆ 㾎%*ίʔυڞ௨Խ ,PEFJOΛར༻͠ɺඞཁͳΠϯελϯεΛ஫ೖ J04ͷ৔߹ class MainViewController: UIViewController, UISearchBarDelegate { private let di = IdolsViewModelDIKt.IdolsViewModelDI(modules: [Main().Module]) override func viewDidLoad() { super.viewDidLoad() viewModel = NativeDIKt.createViewModel(di: di) } ... .BJO7JFX$POUSPMMFSTXJGU %*ϞδϡʔϧΛ6*7JFX$POUSPMMFS಺Ͱੜ੒͠ɺ ࣮૷ͨ͠αϙʔτϝιουͰ7JFX.PEFMΛऔಘ ˒6*Ҏ֎ͷ෦෼͸ ΄΅શͯڞ௨Խ🎉

Slide 25

Slide 25 text

6*ϩδοΫ·Ͱڞ௨Խͯ͠ײͨ͜͡ͱ 㾎༧૝Ҏ্ʹϞμϯͳߏ੒ͷΞϓϦΛָʹ࣮૷Ͱ͖ͨ ඇಉظॲཧɺϏϧυपΓͷͭΒ͍෦෼͕େ͖͘վળ࣮͠༻తʹͳͬͨ "OESPJEJ04Λݸผ࣮૷͢ΔΑΓ΋ѹ౗తʹ଎࣮͘૷Ͱ͖ͨ ͭΒ͍෦෼ΑΓ΋ڞ௨ԽͷԸܙ͕େ͖͍ঢ়ଶʹ͔ͳΓ͍͍ۙͮͯΔ .11ͷ੝Γ্͕Γʹ߹ΘͤͯSE1BSUZϥΠϒϥϦ΋੒௕ͭͭ͋͠Δ Ұ෦ͷ໠ऀ͕௒ؤுͬͯѻ͏ஈ֊͔Βɺ ৽͍ٕ͠ज़ͱָͯ͠͠Έͳ͕Βѻ͑Δஈ֊ʹͳΓͭͭ͋Δ ؾ͕͢Δ ˞4XJGUྺ਺೔ͷݸਓͷײ૝Ͱ͢

Slide 26

Slide 26 text

ͭΒ͔ͬͨ͜ͱ 㾎9DPEFɾ4XJGUɾ6*,JUͳΜ΋Θ͔ΒΜ😇 αϯϓϧΞϓϦͷ࣮૷Ͱ࠷΋࣌ؒΛফඅͨ͠ͷ͕J04ͷ6*࣮૷ 4XJGUͱ,PUMJO͸ࣅ͍ͯΔ͕ɺ"OESPJE4UVEJPͱ9DPEF͸׬શʹผ෺ 㾎,PUMJOͱ4XJGUͷܕͷରԠؔ܎ʹ᠘͕͋Δ ,PUMJOͷ-JTUˠ4XJGUͷ"SSBZ ,PUMJOͷ"SSBZˠ4XJGUͰ͸,PUMJO"SSBZ🤯 ७ਮͳ6*࣮૷ʹ͚ͩूதͰ͖ͨͷ͸ .11͔ͩΒͦ͜ͷར఺͔΋ʜ🤔

Slide 27

Slide 27 text

ࠓޙͷల๬ɾ·ͱΊ 㾎ςετίʔυΛ.11Ͱॻ͖͍ͨ "OESPJEJ04+4ͷϩδοΫΛςετίʔυͰνΣοΫͰ͖Δ ͸ͣ 㾎J04ͷSE1BSUZϥΠϒϥϦ΋.11Ͱѻ͍͍ͨ $PDPB1PET͔Β,PUMJOͷੈքͰJ04༻ϥΠϒϥϦΛѻ͏͜ͱ͕Մೳ 'JSFCBTF౳ͷϥΠϒϥϦΛ.11Ͱѻ͑ͨΒઈରָ͍͠ ϋʔυϧ͕೔ʹ೔ʹԼ͕Γͭͭ͋Δ,PUMJO.11Ͱͷ91MBU։ൃ Έͳ͞Μ΋ָָ͘͠Λͯ͠Έ·ͤΜ͔ʜʁ🥰 5IBOLZPVGPSMJTUFOJOH