Slide 1

Slide 1 text

Jetpack Composeでの画面遷移
 2022/06/30 Jetpack Compose 導入事例【おいしい健康|Retty|ZOZO|アンドパッド】
 株式会社ZOZO
 ZOZOTOWNアプリ部 Android1ブロック
 Androidテックリード
 岩田直樹(いわたん)
 Copyright © ZOZO, Inc. 1

Slide 2

Slide 2 text

© ZOZO, Inc. 株式会社ZOZO
 ZOZOTOWNアプリ部 Android1ブロック
 Androidテックリード
 岩田直樹(いわたん)
 @iwata_n
 普段は二児の父親をやってます。
 Androidアプリのコードを仕事で書いてます。
 2

Slide 3

Slide 3 text

© ZOZO, Inc. https://zozo.jp/
 3 ● ファッションEC
 ● 1,500以上のショップ、8,400以上のブランドの取り扱い
 ● 常時90万点以上の商品アイテム数と毎日平均2,600点以上の新着 商 品を掲載(2022年3月末時点)
 ● ブランド古着のファッションゾーン「ZOZOUSED」や
 コスメ専門モール「ZOZOCOSME」、靴の専門モール
 「ZOZOSHOES」、ラグジュアリー&デザイナーズゾーン
 「ZOZOVILLA」を展開
 ● 即日配送サービス
 ● ギフトラッピングサービス
 ● ツケ払い など


Slide 4

Slide 4 text

© ZOZO, Inc. コンテンツ
 1. 概要と結論
 2. 検討内容
 3. 移行を見据えた実装方法
 4

Slide 5

Slide 5 text

© ZOZO, Inc. コンテンツ
 1. 概要と結論
 2. 検討内容
 3. 移行を見据えた実装方法
 5

Slide 6

Slide 6 text

© ZOZO, Inc. 概要
 Jetpack Composeを使用した画面遷移に関して、公式ドキュメントには以下の記述があります。
 そこで今回は、なぜ公式ドキュメントではFragmentの使用をオススメしているのか、
 公式ドキュメントとは逆にComposeからFragmentを利用する形で検証します。
 また、公式ドキュメントに従ってFragmentをComposableのラッパーとした場合、
 どのようにComposeを実装していき移行するかを画面遷移の観点でまとめます。
 
 『ハイブリッド アプリの場合は、フラグメント ベースの Navigation コンポーネントを使用するとともに、ビューベースの画面、 Compose の画面、およびビューと Compose の両方を使用する画面を保持するフラグメントを使用することをおすすめします。ま ず、アプリの各画面フラグメントをコンポーザブルのラッパーにします。次に、それらの画面すべてを一緒に Navigation Compose に 関連付けて、すべてのフラグメントを削除します。』 Android Developers Compose を使用したナビゲーションより引用 https://developer.android.com/jetpack/compose/navigation?hl=ja#interoperability 
 
 
 6

Slide 7

Slide 7 text

© ZOZO, Inc. 結論
 7 ● Jetpack Composeでの画面遷移は公式ドキュメントの記載通りにFragmentでComposeをラップする実装で行うと問 題点が少なく実装が可能です
 ● 既存実装が残る限りJetpack ComposeのNavigationは使うのが難しい
 ○ Jetpack Composeと既存実装が併存する間、新規画面は移行を考えた実装が必要です


Slide 8

Slide 8 text

© ZOZO, Inc. コンテンツ
 1. 概要と結論
 2. 検討内容
 3. 移行を見据えた実装方法
 8

Slide 9

Slide 9 text

© ZOZO, Inc. 検討内容
 以下の画面遷移の方法について検討しました
 
 1. Compose→Fragmentとなる遷移
 2. Compose→Fragment→Fragmentとなる遷移
 3. Compose→Fragment→Composeとなる遷移
 9

Slide 10

Slide 10 text

© ZOZO, Inc. Compose→Fragmentとなる遷移
 Navigation Componentを使っている場合は公式ドキュメントの通りで良い。
 FragmentManagerを使っている場合も、同様に公式ドキュメント相当の実装で実現可能です。
 https://developer.android.com/jetpack/compose/navigation?hl=ja#navigate-from-Compose
 10 公式サイトの例はComposable側にXMLで定義したIDが入っているので移行時に少し改修が必要になる。
 Compose移行時に改修を不要にするためにコールバックに渡す引数は遷移先ではなく、遷移時に必要なパラメータ をわたすようにする。
 Compose Fragment Compose Fragment FragmentManagerでの遷移もこの コールバック内で出来る Compose内でXMLへ依 存がある

Slide 11

Slide 11 text

© ZOZO, Inc. Compose→Fragment→Fragmentとなる遷移
 11 ● ComposeのAndroidViewにFragmentContainerViewを指定してNavHostFragmentを表示する
 ○ NavHostFragmentを使わず、既存実装のFragmentを表示するとfindNavController()を実行時に、 NavHostFragmentが見つからずクラッシュする
 
 NavHostFragmentを用意してAndroidViewで表示す ることでfindNavController()が動くようにする

Slide 12

Slide 12 text

© ZOZO, Inc. Compose (NavGraph) Compose→Fragment→Fragmentとなる遷移
 NavHostFragmentを使用した場合、一見画面遷移できているように見えるが、
 Compose側が戻るボタンの処理をフックしてしまいFragmentB→Aの戻る操作が正しく行えない。
 
 ①Compose→②FragmentA→③FragmentB→戻るボタンとした際に
 期待値は②のFragmentAが表示されることだが、実際には①Composeまで戻ってしまう。
 12 Compose (AndroidView) 親Fragment(NavHostFragment) ②Fragment A findNavController() ③Fragment B ①Compose Composeの遷移 Navigation Componentの遷移 戻る処理 こちらが戻る処理を フックしてしまう

Slide 13

Slide 13 text

© ZOZO, Inc. Compose→Fragment→Composeとなる遷移
 FragmentからJetpack Composeへ遷移する際にFragment側に改修が必要になる。
 例えばリストがFragment、詳細がComposeで実装されていた場合などで、
 リストから詳細へ遷移する際にクリックイベントをJetpack Comoseへ引き回してくる必要がある。
 → Fragment Result APIで取れるが、既存実装を改修するのであればCompose化を考えたほうが良さそう。
 
 13 Compose (NavGraph) Compose (AndroidView) Fragment (リスト画面) Compose (詳細画面) 選択結果 Fragmentでの選択結果をFragment Result APIでComposeに渡す

Slide 14

Slide 14 text

© ZOZO, Inc. 検討結果
 ● Composeで既存実装をラップする実装をするには、既存実装側に手を入れる必要があったり、戻る操作を正しく実現 するのに難がある
 ○ 公式ドキュメントではFragmentでComposableをラップするのをオススメしていたと思われる
 ○ 大半の画面をComposeで実装しても、移行するのが辛い既存実装があると完全にComposeのNavigationに移行は できない
 ● 併用が必要になるのが間違いないので新規実装時にComposeへ移行することを見据えた実装が必要になる
 
 14

Slide 15

Slide 15 text

© ZOZO, Inc. コンテンツ
 1. 概要と結論
 2. 検討内容
 3. 移行を見据えた実装方法
 15

Slide 16

Slide 16 text

© ZOZO, Inc. 移行を見据えて既存実装とJetpack Composeを併用する
 新しい画面の実装手順
 1. Jetpack ComposeでステートレスなComposableをScreenとして実装する
 2. ViewModelを実装する
 3. Screenと、ステートや遷移イベントと紐付けを行うRouteを実装する
 4. Jetpack Compose内での遷移定義するNavigationを実装する
 5. RouteにThemeとNavigationを紐付けるFragmentを実装する
 6. 既存の画面遷移方法で新規Fragmentへ遷移する
 
 
 16 既存NavHostFragment 既存Fragment (手を加えない) 新規Fragment ComposeView (NavHost) Compose Screen A Compose Screen B 新規Fragment Composeの遷移 Navigation Componentの遷移 戻る処理

Slide 17

Slide 17 text

© ZOZO, Inc. Jetpack ComposeでステートレスなScreenを実装する
 ● Screenは引数でステートを受け取り、イベントをコールバック で返す
 ● ScreenではViewModelを引数に取らない
 ○ Previewをしやすくする
 ○ 不要な再Composeを減らす
 
 17 既存NavHostFragment 既存 Fragment 新規Fragment ComposeView (NavHost) Compose Screen A Compose Screen B 新規 Fragment Tips
 ● Screenの単位でTopBarを定義した方がタイトルやメニューを各Screenから TopBarを管理する画面へ状態を伝える必要がなくなるので楽になる


Slide 18

Slide 18 text

© ZOZO, Inc. ViewModelを実装する
 ● 画面の状態を管理するUiStateをStateFlowで提供する
 ● 副作用を流すためのEffectをSharedFlowで提供する
 
 
 18

Slide 19

Slide 19 text

© ZOZO, Inc. Routeの実装
 ● Screenとステートや遷移イベントと紐付けを行うRouteを実装
 
 19 既存NavHostFragment 既存 Fragment 新規Fragment ComposeView (NavHost) Compose Screen A Compose Screen B 新規 Fragment Navigation ComponentではViewModelで遷移時のパラメータ (id) を受け取れなかったので Routeで指定できるようにする ここでScreenにUIの状態を渡す

Slide 20

Slide 20 text

© ZOZO, Inc. NavigationGraphの定義
 ● NavGraphBuilderの拡張関数で画面遷移の定義を行う
 ● routeで{}を使うことで画面遷移時に渡すパラメータを設定できるが、FragmentでstartDestinationに遷移してきた際 に値が取れなかったので、拡張関数のグラフで値を受け取る対策をした実装で定義する
 20 理想形 対策した実装 既存NavHostFragment 既存 Fragment 新規Fragment ComposeView (NavHost) Compose Screen A Compose Screen B 新規 Fragment

Slide 21

Slide 21 text

© ZOZO, Inc. Fragmentの実装
 ● FragmentのonCreateViewでNavHostを定義したComposeViewを返す
 ● Composeに完全移行した際には不要になる
 ○ Fragmentでテーマを設定することでComposeに移行時に大本でComposableのテーマを設定するだけで全体に 反映できるようになる
 21 既存NavHostFragment 既存 Fragment 新規Fragment ComposeView (NavHost) Compose Screen A Compose Screen B 新規 Fragment

Slide 22

Slide 22 text

© ZOZO, Inc. 完全にComposeに移行する
 移行手順
 1. 各フローごとにNavGraphBuilderの拡張関数でグラフを定義する
 2. アプリ全体の遷移を管理するNavHostで各フローを定義する
 3. 一番大本のComposableでテーマを設定する
 4. Fragmentを削除し、Navigation Componentを外す
 22

Slide 23

Slide 23 text

© ZOZO, Inc. まとめ
 ● Jetpack Composeでの画面遷移は公式ドキュメントの記載通りにFragmentでComposeをラップする実装で行うと問 題点が少なく実装が可能です
 ● 既存実装が残る限りJetpack ComposeのNavigationは使うのが難しい
 ○ Jetpack Composeと既存実装が併存する間、新規画面は移行を考えた実装が必要です
 
 23

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

© ZOZO, Inc. Appendix
 25

Slide 26

Slide 26 text

© ZOZO, Inc. Navigationの定義方法
 1. 機能やフローなど意味のある単位ごとにNavGraphBuilderの拡張関数を定義する
 2. NavGraphBuilderの拡張関数を使ってアプリ全体の画面遷移をまとめる
 26 個別の機能やフローごとに拡張関数を定義 AppNavHostで全体をまとめる

Slide 27

Slide 27 text

© ZOZO, Inc. BottomNavigation
 ScaffoldのbottomBarにBottomNavigationを指定するだけで作れるので便利。
 27 enumで定義した設定値を forEachす るだけで要素が作れて便利 click時にnavControllerで遷移させる enumに遷移先、テキスト、アイコンを 定義する