Slide 1

Slide 1 text

Android値受け渡し大全 ~ 設計を制する者が「渡す」を制す 〜 登壇者:STORES 株式会社 Androidエンジニア みっちゃん 1

Slide 2

Slide 2 text

自己紹介 ● 名前:みっちゃん ● 経歴: ○ 22新卒でSTORES 株式会社に入社 ○ STORES 決済 や ブランドアプリ の開発 ○ Android歴は4年目くらい ○ DroidKaigiスタッフもしてます! X(Twitter): 🔗@mimimi_engineer 2/103

Slide 3

Slide 3 text

本セッションの目的 Androidアプリ開発において「この値、別のクラスでも参照したい!」 というシチュエーション、いっぱいありますよね?!?! 3/103

Slide 4

Slide 4 text

本セッションの目的 「値を渡したい」時に一番最初に思いつくのはなんでしょう? → メソッドの引数に渡す! どんなシチュエーションでもそれで乗り切れますか...? 4/103

Slide 5

Slide 5 text

本セッションの目的 例えば... ユーザーから入力された値を保存したいので、ViewModelのsave() メソッドに入力データを渡したい! → 「メソッドの引数に渡す」で󰢐そう! 5/103

Slide 6

Slide 6 text

本セッションの目的 例えば... ニュース詳細画面を開いてニュースが「既読」状態になったら、 ニュース一覧画面に戻った時も既読状態になっていてほしい = 「既読」の情報を2つの画面から参照したい! → 「引数に渡す」手段で本当に大丈夫?? 6/103

Slide 7

Slide 7 text

本セッションの目的 このように、値やデータを別のクラスでも参照したい!使いたい! というシチュエーションはたくさんあります! 1つの手段しか持っていないと、 保守性や可読性の観点からアプリに悪影響を与えていることにも気付けない! どんな手段があるのか・その手段はどういう観点で良い or 悪いのか、 というのが分かれば、その時の状況やプロダクトの性質に応じて 確信を持って最適な手段を選択することができる! 7/103

Slide 8

Slide 8 text

本日のゴール ● 値の受け渡し方法について色々な手段があることを知っている ● 「良い設計」や「Androidアプリ特有の性質」の観点から、それぞれ の方法の良し悪しを評価できる 8/103

Slide 9

Slide 9 text

本セッションの対象者 ● ⭐ 初級〜中級者:新しい学びや、思考の整理になります ● 上級者:改めて思考の整理になったり、後輩に教える時の材料にも なります 9/103

Slide 10

Slide 10 text

● 値を渡す色々な方法 ● 値を渡すだけじゃダメ!「いいね問題」の解決方法どっちが良い? ● 解決方法を評価するための観点2つ ● 「いいね問題」の解決方法をもう一度評価してみよう ● まとめ ● 参考文献 本日のお品書き 10/103

Slide 11

Slide 11 text

● 値を渡す色々な方法 ● 値を渡すだけじゃダメ!「いいね問題」の解決方法どっちが良い? ● 解決方法を評価するための観点2つ ● 「いいね問題」の解決方法をもう一度評価してみよう ● まとめ ● 参考文献 本日のお品書き 11/103

Slide 12

Slide 12 text

● 値を渡す色々な方法 1. メソッドの引数に渡す 2. 画面遷移時に渡す 3. Pub-Sub 4. DI 5. データホルダーを使って受け流す 本日のお品書き 12/103

Slide 13

Slide 13 text

● 値を渡す色々な方法 1. メソッドの引数に渡す 2. 画面遷移時に渡す 3. Pub-Sub 4. DI 5. データホルダーを使って受け流す 本日のお品書き 13/103

Slide 14

Slide 14 text

1. メソッドの引数に渡す ● 最も基本的な方法 ● 例:ユーザーの入力情報を更新するためにViewModelのメソッドに渡す 値を渡す色々な方法 14/103

Slide 15

Slide 15 text

● 値を渡す色々な方法 1. メソッドの引数に渡す 2. 画面遷移時に渡す 3. Pub-Sub 4. DI 5. データホルダーを使って受け流す 本日のお品書き 15/103

Slide 16

Slide 16 text

2. 画面遷移時に渡す ● Activityベース ○ Intent ● Fragmentベース ○ FragmentTransaction / NavigationComponent ● Composeベース ○ NavigationCompose 値を渡す色々な方法 17/103

Slide 17

Slide 17 text

2. 画面遷移時に渡す Activityベース:Intentを使う 値を渡す色々な方法 18/103

Slide 18

Slide 18 text

2. 画面遷移時に渡す Activityベース:Intentを使う 値を渡す色々な方法 19/103

Slide 19

Slide 19 text

2. 画面遷移時に渡す Activityベース:Intentを使う 値を渡す色々な方法 20/103

Slide 20

Slide 20 text

2. 画面遷移時に渡す Fragmentベース:FragmentTransaction, NavigationComponent 値を渡す色々な方法 21/103

Slide 21

Slide 21 text

2. 画面遷移時に渡す Fragmentベース:FragmentTransaction, NavigationComponent 値を渡す色々な方法 22/103

Slide 22

Slide 22 text

2. 画面遷移時に渡す Fragmentベース:FragmentTransaction, NavigationComponent 値を渡す色々な方法 23/103

Slide 23

Slide 23 text

2. 画面遷移時に渡す Fragmentベース:FragmentTransaction, NavigationComponent 値を渡す色々な方法 24/103

Slide 24

Slide 24 text

2. 画面遷移時に渡す Fragmentベース:FragmentTransaction, NavigationComponent 値を渡す色々な方法 nav_graph.xml Fragment 25/103

Slide 25

Slide 25 text

2. 画面遷移時に渡す Fragmentベース:FragmentTransaction, NavigationComponent 値を渡す色々な方法 nav_graph.xml Fragment 26/103

Slide 26

Slide 26 text

2. 画面遷移時に渡す Fragmentベース:FragmentTransaction, NavigationComponent 値を渡す色々な方法 nav_graph.xml Fragment 27/103

Slide 27

Slide 27 text

2. 画面遷移時に渡す Composeベース:NavigationCompose 値を渡す色々な方法 28/103

Slide 28

Slide 28 text

2. 画面遷移時に渡す Composeベース:NavigationCompose 値を渡す色々な方法 29/103

Slide 29

Slide 29 text

2. 画面遷移時に渡す Composeベース:NavigationCompose 値を渡す色々な方法 30/103

Slide 30

Slide 30 text

● 値を渡す色々な方法 1. メソッドの引数に渡す 2. 画面遷移時に渡す 3. Pub-Sub 4. DI 5. データホルダーを使って受け流す 本日のお品書き 31/103

Slide 31

Slide 31 text

3. Pub-Sub Pub-Sub(Publish-Subscribe)モデルとは? 値を渡す色々な方法 参考:e-words Pub/Subモデル 32/103

Slide 32

Slide 32 text

3. Pub-Sub Pub-Sub(Publish-Subscribe)モデルとは? → 情報の発信側と受信側を直接つなげずにやり取りする仕組み 値を渡す色々な方法 33/103

Slide 33

Slide 33 text

3. Pub-Sub Androidアプリ開発では、EventBusが使われる(最近は使われてない) 値を渡す色々な方法 Publisher Subscriber EventBus イベント イベント 34/103

Slide 34

Slide 34 text

3. Pub-Sub 例:クラッシュイベントをアプリ内の別のクラスで受け取る 値を渡す色々な方法 35/94

Slide 35

Slide 35 text

3. Pub-Sub 例:クラッシュイベントをアプリ内の別のクラスで受け取る 値を渡す色々な方法 36/94

Slide 36

Slide 36 text

3. Pub-Sub 例:クラッシュイベントをアプリ内の別のクラスで受け取る 値を渡す色々な方法 37/103

Slide 37

Slide 37 text

3. Pub-Sub 例:クラッシュイベントをアプリ内の別のクラスで受け取る 値を渡す色々な方法 38/103

Slide 38

Slide 38 text

● 値を渡す色々な方法 1. メソッドの引数に渡す 2. 画面遷移時に渡す 3. Pub-Sub 4. DI 5. データホルダーを使って受け流す 本日のお品書き 39/103

Slide 39

Slide 39 text

4. DI(Dependency Injection) ● 別のクラスの値を参照したい時に、Daggerを利用して、そのクラスのイン スタンスを別のクラスに注入する 値を渡す色々な方法 // HogeClass HogeClass { val hoge = “hoge!!” … … } // FooClass FooClass @Inject constructor( val hoge: Hoge ) { // 参照できた val hoge = hoge.hoge // hoge!! } DI 40/103

Slide 40

Slide 40 text

4. DI(Dependency Injection) ● 例:アプリ名を取得するためにcontextのインスタンスをDaggerHiltで 注入する 値を渡す色々な方法 41/103

Slide 41

Slide 41 text

4. DI(Dependency Injection) ● 例:アプリ名を取得するためにcontextのインスタンスをDaggerHiltで 注入する 値を渡す色々な方法 42/103

Slide 42

Slide 42 text

● 値を渡す色々な方法 1. メソッドの引数に渡す 2. 画面遷移時に渡す 3. Pub-Sub 4. DI 5. データホルダーを使って受け流す 本日のお品書き 43/103

Slide 43

Slide 43 text

5. データホルダーを使って受け流す ● データホルダー:LiveData・StateFlow ● 例:DBの値をStateFlowに詰めてUIに受け流す 値を渡す色々な方法 44/103

Slide 44

Slide 44 text

5. データホルダーを使って受け流す ● データホルダー:LiveData・StateFlow ● 例:DBの値をStateFlowに詰めてUIに受け流す 値を渡す色々な方法 45/103

Slide 45

Slide 45 text

5. データホルダーを使って受け流す ● データホルダー:LiveData・StateFlow ● 例:DBの値をStateFlowに詰めてUIに受け流す 値を渡す色々な方法 46/103

Slide 46

Slide 46 text

5. データホルダーを使って受け流す ● データホルダー:LiveData・StateFlow ● 例:DBの値をStateFlowに詰めてUIに受け流す 値を渡す色々な方法 47/103

Slide 47

Slide 47 text

● 値を渡す色々な方法 ● 値を渡すだけじゃダメ!「いいね問題」の解決方法どっちが良い? ● 解決方法を評価するための観点2つ ● 「いいね問題」の解決方法をもう一度評価してみよう ● まとめ ● 参考文献 本日のお品書き 48/103

Slide 48

Slide 48 text

やれることをやるだけではアプリのクオリティを維持できない! メリットやデメリットを理解した上でやり方を選ばないと、アプリの 保守性や可読性に悪影響を与えていることにすら気付けない...! 「いいね問題」を例に、値を渡す方法を評価する観点について 学んでいきましょう! 値を渡すだけじゃダメ!~ いいね問題の解決方法どっちが良い? ~ 49/103

Slide 49

Slide 49 text

いいね問題とは? ● イベント一覧画面 と いいね一覧画面 がある ● イベント画面のアイテムを「いいね」 して、いいね画面に行くと、 いいね画面のアイテムにも「いいね」 のマークがある 値を渡すだけじゃダメ!~ いいね問題の解決方法どっちが良い? ~ いいね いいね 50/103

Slide 50

Slide 50 text

いいね問題とは? ● 2つの画面で「いいね」という 状態に整合性が取れている必要がある ● それをどうやって実現するか? → 「いいね問題」と呼ばれている 値を渡すだけじゃダメ!~ いいね問題の解決方法どっちが良い? ~ いいね いいね 51/103

Slide 51

Slide 51 text

いいね問題とは? ● いいね機能だけが「いいね問題」 になるわけではない! ● 冒頭のスライドの既読の例も 「いいね問題」の1つ! 値を渡すだけじゃダメ!~ いいね問題の解決方法どっちが良い? ~ 52/103

Slide 52

Slide 52 text

いいね問題の解決方法2つ提案! A. 画面遷移時に「いいね」の情報を渡す B. データホルダーを使ってDBから「いいね」の情報を受け流す 値を渡すだけじゃダメ!~ いいね問題の解決方法どっちが良い? ~ 53/103

Slide 53

Slide 53 text

いいね問題の解決方法2つ提案! A. 画面遷移時に「いいね」の情報を渡す B. データホルダーを使ってDBから「いいね」の情報を受け流す 値を渡すだけじゃダメ!~ いいね問題の解決方法どっちが良い? ~ 紹介した方法のうち、この2つ! A B 54/103

Slide 54

Slide 54 text

どっちが良いと思いますか??? A. 画面遷移時に「いいね」の情報を渡す B. データホルダーを使ってDBから「いいね」の情報を受け流す 55/103

Slide 55

Slide 55 text

どっちが良いか、理由を答えられますか??? A. 画面遷移時に「いいね」の情報を渡す B. データホルダーを使ってDBから「いいね」の情報を受け流す 56/103

Slide 56

Slide 56 text

● 値を渡す色々な方法 ● 値を渡すだけじゃダメ!「いいね問題」の解決方法どっちが良い? ● 解決方法を評価するための観点2つ ● 「いいね問題」の解決方法をもう一度評価してみよう ● まとめ ● 参考文献 本日のお品書き 57/103

Slide 57

Slide 57 text

どっちが良いか、判断するための観点2つ 観点1. 良い設計 の条件を満たしているか 観点2. Androidアプリ特有の問題 を解決しているか 58/103

Slide 58

Slide 58 text

1. 良い設計の要素 ○ SSOT ○ UDF 2. Androidアプリ固有の問題 ○ ライフサイクル ○ 値を保持する方法 解決方法を評価するための観点2つ 59/103

Slide 59

Slide 59 text

1. 良い設計の要素 ○ SSOT ○ UDF 2. Androidアプリ固有の問題 ○ ライフサイクル ○ 値を保持する方法 解決方法を評価するための観点2つ 60/103

Slide 60

Slide 60 text

今回は「値の受け渡し」という観点に絞って 良い設計の要素を紹介します! ● SSOT(Single Source Of Truth) ● UDF(Unidirectional Data Flow) 良い設計の要素2つ! 61/103

Slide 61

Slide 61 text

● 正確な情報源を一つだけ作成しよう、という意味 ● SSOTのみがそのデータの変更を行える ● SSOTは不変の型を使用してそのデータを公開する ● メリット ○ データの変更を追跡できやすく、バグを発見しやすい ○ 他の型によって改ざんされないようにデータを保護できる SSOT(信頼できる唯一の情報源) 参考:Android Developers 信頼できる唯一の情報源 62/103

Slide 62

Slide 62 text

SSOT(信頼できる唯一の情報源) 参考:Android Developers 信頼できる唯一の情報源 どういうコト? 63/103

Slide 63

Slide 63 text

SSOT(信頼できる唯一の情報源) list … … 64/103

Slide 64

Slide 64 text

SSOT(信頼できる唯一の情報源) list … … 65/103

Slide 65

Slide 65 text

SSOT(信頼できる唯一の情報源) list … … detail 66/103

Slide 66

Slide 66 text

SSOT(信頼できる唯一の情報源) list … … detail 67/103

Slide 67

Slide 67 text

SSOT(信頼できる唯一の情報源) DB list … … detail 68/103

Slide 68

Slide 68 text

SSOT(信頼できる唯一の情報源) DB list … … detail ←このDBがSSOTだよ!というコト 69/103

Slide 69

Slide 69 text

● 状態はデータ層からUI層へ一方向に流れる(DBから読取り) ● データを変更するイベントはUI層からデータ層へ流れる(DBへ書込み) ● SSOTとセットの考え方 UDF(単方向データフロー) 参考:Android Developers 単方向データフロー 70/103

Slide 70

Slide 70 text

DB list … … detail UDF(単方向データフロー) 一方通行! 71/103

Slide 71

Slide 71 text

1. 良い設計の要素 ○ SSOT ○ UDF 2. Androidアプリ固有の問題 ○ ライフサイクル ○ 値を保持する方法 解決方法を評価するための観点2つ 72/103

Slide 72

Slide 72 text

値の受け渡しだけではなく、値の保持についても考える必要がある! → Androidアプリ固有の問題としてライフサイクルがあるから!! Androidアプリ固有の問題 と 値の保持 73/103

Slide 73

Slide 73 text

ライフサイクル → 画面回転などのコンフィギュレーション チェンジでもonDestroyが呼ばれて、Activityの インスタンスはメモリから破棄される 参考:Android Developers アクティビティのライフサイクル 74/103

Slide 74

Slide 74 text

ライフサイクル → 画面回転などのコンフィギュレーション チェンジでもonDestroyが呼ばれて、Activityの インスタンスはメモリから破棄される 参考:Android Developers アクティビティのライフサイクル → 場合によっては渡されてきたデータが消えてしまう?! 75/103

Slide 75

Slide 75 text

値を保持する方法についても考えないといけない ● StateHolderで保持 ● ストレージに保持 ● savedStateHandle・onSaveInstanceState・rememberSavable 76/103

Slide 76

Slide 76 text

値を保持する方法 ● StateHolderで保持 ● ストレージに保持 ● savedStateHandle・onSaveInstanceState・rememberSavable 77/103

Slide 77

Slide 77 text

StateHolderで保持 StateHolder = ViewModel・UIState・StateFlow 画面回転によってActivityのインスタンスは破棄されるが、 ViewModelは破棄されないので、ViewModel側に値を保持する という方法 アプリキルは(ViewModelが破棄されるので)乗り越えられないけど 画面回転は乗り越えられる 78/103

Slide 78

Slide 78 text

値を保持する方法 ● StateHolderで保持 ● ストレージに保持 ● savedStateHandle・onSaveInstanceState・rememberSavable 79/103

Slide 79

Slide 79 text

ストレージに保持 オンメモリ VS ストレージ ● オンメモリ:変数で値を保持する・onDestroyで破棄される ● ストレージ:永続化すること・onDestoryで破棄されない ○ Room・SQLite・SharedPreference・DataStore を使う 80/103

Slide 80

Slide 80 text

値を保持する方法 ● StateHolderで保持 ● ストレージに保持 ● savedStateHandle・onSaveInstanceState・rememberSavable 81/103

Slide 81

Slide 81 text

savedStateHandle・onSaveInstanceState・rememberSavable どれも一時的に値を保持して画面回転を乗り越えることができる≠永続化 ● savedStateHandle ○ ViewModelで値を保持 ● onSaveInstanceState ○ Activity・Fragmentで値を保持 ● rememberSavable ○ JetpackComposeのComposable内で値を保持 82/103

Slide 82

Slide 82 text

1. 良い設計の要素 ○ SSOT ○ UDF 2. Androidアプリ固有の問題 ○ ライフサイクル ○ 値を保持する方法 値の受け渡し方法を評価するための観点2つ 83/103

Slide 83

Slide 83 text

皆さんにもう一度、質問します 84/103

Slide 84

Slide 84 text

いいね問題とは? ● 2つの画面で「いいね」という 状態に整合性が取れている必要がある ● それをどうやって実現するか? → 「いいね問題」と呼ばれている 値を渡すだけじゃダメ!~ いいね問題の解決方法どっちが良い? ~ いいね いいね 85/103

Slide 85

Slide 85 text

どっちが良いと思いますか??? A. 画面遷移時に「いいね」の情報を渡す B. データホルダーを使ってDBから「いいね」の情報を受け流す 86/103

Slide 86

Slide 86 text

どっちが良いか、理由を答えられますか??? A. 画面遷移時に「いいね」の情報を渡す B. データホルダーを使ってDBから「いいね」の情報を受け流す 87/103

Slide 87

Slide 87 text

先ほど勉強した2つの観点を使って もう一度考えてみましょう! 88/103

Slide 88

Slide 88 text

● 値を渡す色々な方法 ● 値を渡すだけじゃダメ!「いいね問題」の解決方法どっちが良い? ● 解決方法を評価するための観点2つ ● 「いいね問題」の解決方法をもう一度評価してみよう ● まとめ ● 参考文献 本日のお品書き 89/103

Slide 89

Slide 89 text

A. 画面遷移時に「いいね」の情報を渡す B. データホルダーを使ってDBから「いいね」の情報を受け流す 「いいね問題」の解決方法をもう一度評価してみよう 90/103

Slide 90

Slide 90 text

A. 画面遷移時に「いいね」の情報を渡す 91/103

Slide 91

Slide 91 text

1. 良い設計の要素 ○ SSOT→SSOTがないので❌ ○ UDF→「いいね」情報の流れが一方通行でないので❌ 2. Androidアプリ固有の問題 と 値の保持 ○ ライフサイクルを乗り越えて値を保持できる →❓❓❓ A. 画面遷移時に「いいね」の情報を渡す 92/103

Slide 92

Slide 92 text

1. 良い設計の要素 ○ SSOT→SSOTがないので❌ ○ UDF→「いいね」情報の流れが一方通行でないので❌ 2. Androidアプリ固有の問題 と 値の保持 ○ ライフサイクルを乗り越えて値を保持できる →ViewModel側で状態を保持してれば画面回転は乗り越えられる が、永続化してないのでアプリキルするといいね情報が失われる A. 画面遷移時に「いいね」の情報を渡す 93/103

Slide 93

Slide 93 text

B. データホルダーを使ってDBから「いいね」の情報を受け流す DB 94/103

Slide 94

Slide 94 text

1. 良い設計の要素 ○ SSOT→SSOTであるDBがあるので⭕ ○ UDF→「いいね」情報の流れが一方通行なので⭕ 2. Androidアプリ固有の問題 と 値の保持 ○ ライフサイクルを乗り越えて値を保持できる →DBに永続化しており、画面回転もアプリキルも乗り越えられる ので⭕ B. データホルダーを使ってDBから「いいね」の情報を受け流す 95/103

Slide 95

Slide 95 text

A. 画面遷移時に「いいね」の情報を渡す → ❌ SSOT・UDFを満たしていない。ライフサイクルを考慮した値の保持ができていな い。 B. データホルダーを使ってDBから「いいね」の情報を受け流す → ⭕ SSOT・UDFを満たしている。ライフサイクルを考慮した値の保持ができている。 「いいね問題」の解決方法を評価した結果 96/103

Slide 96

Slide 96 text

設計やAndroidアプリの特徴を考慮して値の受け渡し 方法の良し悪しを評価することができましたね! 97/103

Slide 97

Slide 97 text

値の受け渡し方法について考える上で今回は「良い設計」と 「Androidアプリの特徴」に絞って触れた。 これ以外の観点で「プロダクトの特徴」も重要。 つまり「良い設計」や「Androidアプリの特徴」の観点で ❌が含まれるからといって、絶対的に悪だ!とは言い切れない。 プロダクトの特徴や様々なコストも考慮して意思決定しよう!! 🚨第3の観点:「プロダクトの特徴」 98/103

Slide 98

Slide 98 text

● 値を渡す色々な方法 ● 値を渡すだけじゃダメ!「いいね問題」の解決方法どっちが良い? ● 解決方法を評価するための観点2つ ● 「いいね問題」の解決方法をもう一度評価してみよう ● まとめ ● 参考文献 本日のお品書き 99/103

Slide 99

Slide 99 text

● Androidアプリ開発では値を受け渡したいシチュエーションがたくさんある ● 値を受け渡す方法は色々ある ○ メソッドの引数に渡す ○ 画面遷移時に渡す ○ Pub-Sub系 ○ DI ○ データホルダーを使って受け流す まとめ 100/103

Slide 100

Slide 100 text

● どの方法が良いかを見極める上で「良い設計」と「Andoroidアプリ固有の特徴」 の2つの観点がある ● 良い設計 の観点 ○ UDF(単方向データフロー) ○ SSOT(信頼できる唯一の情報源) ● Androidアプリ固有の特徴 ○ ライフサイクルを乗り越えて値を保持する まとめ 101/103

Slide 101

Slide 101 text

● https://e-words.jp/w/Pub-Sub%E3%83%A2%E3%83%87%E3%83%AB.html ● https://developer.android.com/topic/architecture?hl=ja#single-source-of-truth ● https://developer.android.com/topic/architecture?hl=ja#unidirectional-data-flow ● https://developer.android.com/guide/components/activities/activity-lifecycle?hl =ja#ondestroy ● https://github.com/iroha-168/PickUpConnpassEvents 参考文献 102/103

Slide 102

Slide 102 text

ご清聴ありがとうございました! 103/103