Slide 1

Slide 1 text

Fluxアーキテクチャに Jetpack Composeを導入してみた 【 Y U M E M I x S a n s a n T e c h M e e t u p 】 A n d r o i d 開 発 に お け る チ ャ レ ン ジ を 語 る Sansan株式会社 技術本部 Mobile Applicationグループ プロダクト開発Androidエンジニア 古川 真次

Slide 2

Slide 2 text

自己紹介 ● 古川 真次(ふるしん) ● @furusin_oriver ● Sansan,Inc. Android Engineer, Team Leader ● 大阪府在住 ● 趣味:勉強会の主催 ○ GDG Osaka オーガナイザー ○ Kansai.kt オーガナイザー

Slide 3

Slide 3 text

このセッションのきっかけ - サンプル見てもMVVMばっかり - ちまたの勉強会のセッションを見てもMVVMありきばっかり - 「Jetpack Composeの導入のためにアーキテクチャをMVVMに変えまし た」とか見聞きした - 🤔🤔🤔🤔🤔 - Jetpack Composeが特定のアーキテクチャでしか使えないなんてことは 絶対ないだろう - ようし、SansanはFluxだからFluxで導入した事例を発信しよう←イマココ

Slide 4

Slide 4 text

前提知識

Slide 5

Slide 5 text

Jetpack Compose?

Slide 6

Slide 6 text

● 機能の実装はKotlin(Java)、UIの実装はXMLと別れていた 従来のAndroid UI設計の問題点 MainActivity.kt class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } } activity_main.xml

Slide 7

Slide 7 text

● 機能の実装はKotlin(Java)、UIの実装はXMLと別れていた 従来のAndroid UI設計の問題点 MainActivity.kt class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } } activity_main.xml ● KotlinとLayout XMLを行ったり来たりしないといけない ● ミスったらKotiln上の状態とLayout XML上の状態がズレる

Slide 8

Slide 8 text

● 全てを一元管理 ○ 状態が変わったらViewも一緒に変わる Single source of truth

Slide 9

Slide 9 text

Jetpack Composeで書いてみよう MainActivity.kt class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { JetpackComposeSampleTheme { // A surface container using the 'background' color from the theme Surface(color = MaterialTheme.colors.background) { Greeting("Android") } } } } } @Composable fun Greeting(name: String) { Text(text = "Hello $name!") }

Slide 10

Slide 10 text

Fluxアーキテクチャ?

Slide 11

Slide 11 text

- 処理の流れが一方通行 - 「データの表示」にフォーカスできる 前提知識:Fluxアーキテクチャ? 出典:Sansan AndroidにおけるFlux移行 https://buildersbox.corp-sansan.com/entry/2019/12/13/110000

Slide 12

Slide 12 text

ComposeはFluxと似てる 出典:Using state in Jetpack Compose/ Android デベロッパー https://developer.android.com/codelabs/jetpack-compose- state?hl=ja&continue=https%3A%2F%2Fdeveloper.android.com%2Fcourses%2Fpathways%2Fcompose%3Fhl% 3Dja%23codelab-https%3A%2F%2Fdeveloper.android.com%2Fcodelabs%2Fjetpack-compose-state#2

Slide 13

Slide 13 text

実際のコード

Slide 14

Slide 14 text

既存のFlux + DataBinding(ViewBinding)のイメージ class SampleStateStore() : ViewModel() { var data: LiveData = MutableLiveData() fun on(action: Action<*>) { when (action) { is SampleAction -> { (data as MutableLiveData).value = action.payload } } } } class SampleActivity sampleStateStore.data.observe(this, { state -> when (state) { is SampleState.Success -> binding.toolbar.title = state.title } })

Slide 15

Slide 15 text

- 各Composable関数でStoreをobserveAsState()する Jetpack Compose with Flux(置き換え) @Composable fun Greeting() { val stateObserver = sampleStateStore.data.observeAsState() when (val sampleState = stateObserver.value) { is SampleState.Success -> Text(text = "Hello ${sampleState.title}!") SampleState.Error -> Text(text = "Hello Android!") } }

Slide 16

Slide 16 text

- 各Composable関数でStoreをobserveAsState()する Jetpack Compose with Flux(置き換え) @Composable fun Greeting() { val stateObserver = sampleStateStore.data.observeAsState() when (val sampleState = stateObserver.value) { is SampleState.Success -> Text(text = "Hello ${sampleState.title}!") SampleState.Error -> Text(text = "Hello Android!") } }

Slide 17

Slide 17 text

LiveData.observeAsState() @Composable fun LiveData.observeAsState(): State = observeAsState(value) @Composable fun LiveData.observeAsState(initial: R): State { val lifecycleOwner = LocalLifecycleOwner.current val state = remember { mutableStateOf(initial) } DisposableEffect(this, lifecycleOwner) { val observer = Observer { state.value = it } observe(lifecycleOwner, observer) onDispose { removeObserver(observer) } } return state }

Slide 18

Slide 18 text

Jetpack Compose with Flux(置き換え) @Composable fun Toolbar() { Surface { TopAppBar { val state = sampleStateStore.data.observeAsState() when (val value = state.value) { is SampleState.Success -> { title = value.title } } } } }

Slide 19

Slide 19 text

- LiveData - LiveData.observeAsState(initial: R): State - Flow - StateFlow.collectAsState(initial: R): State - RxJava2 - Observable?.subscribeAsState(initial: R?) observeAsStateは他にもある

Slide 20

Slide 20 text

- Fluxでもアーキテクチャを気にせずJetpack Composeが使えた - 「MVVMでなければならない」というわけではない - 想像してたより簡単に導入できた! 結論

Slide 21

Slide 21 text

- Using state in Jetpack Compose - observeAsState()してる https://developer.android.com/codelabs/jetpack-compose- state?hl=ja&continue=https%3A%2F%2Fdeveloper.android.com%2Fcourses%2Fpathways%2Fcompose%3F hl%3Dja%23codelab-https%3A%2F%2Fdeveloper.android.com%2Fcodelabs%2Fjetpack-compose-state#3 - Sansan AndroidにおけるFlux移行(Sansan Builders Blog) https://buildersbox.corp-sansan.com/entry/2019/12/13/110000 参考文献

Slide 22

Slide 22 text

(Tips)ほしいComposableの探し方 - リファレンスから探す - https://developer.android.com/jetpack/androidx/releases/compose - 日本語は更新が遅れてることもあるので英語で見よう - だいたいMaterialを覗いたらある(ButtonとかDropdownMenuとか)

Slide 23

Slide 23 text

No content