はじめてのKotlin + Android（画面遷移）

# はじめに
今までは試合に出る際はGoogleCalendarの説明欄に試合の振り返りをメモっていた。
![screen.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883681/8577c9bb-6f13-eea7-c5e2-7e388a5fed11.png)

が、後で見返すのが辛くメモるだけ。
勉強がてらアプリでも作ってみようかな、と思ったのがきっかけです。

メモがてらハマったところとか感動したところを（赤裸々に）残していきたいと思います。
多分有識者から見たら、「なんでそんな意味わかんないことしてるの？ちゃんとリファレンスをしっかり読み込みなよ」とツッコミを頂くんだろうなぁ

# アプリで実現したいこと

最低限以下は実現したいと考えました。
- 出た試合の結果や振り返りを残せる
- 試合の時に意識すべきことをチェックリストで表示（体が覚えたと思ったことも後で見返してニンマリしたい）

今まではGoogleCalendarにスケジュール登録していたのをこのアプリで管理できるようにする・・・とかも考えましたが、カレンダーを実装したところで（自分が）使う未来が見えなかったので放置。

# 制約（？）条件
Androidアプリを実装したのが5年以上前で、Fragmentを使ったこともなければSQLiteを使ったこともない。
ということで、折角作るならやったことないことにチャレンジしてみよう！ということで以下を制約として自らに掲げます
1. Fragmentを使う
2. SQLiteに諸々保存する
3. クラウドにデータ保持とかはナシ（やりたいことに対してオーバースペックで時間かかりそうだから）
4. 誰かに共有とかもナシ。あくまで自分の日記を見返す感覚のアプリ
5. ガッツリした設計はせずにいきなり実装（設計は比較的好きだけど、設計完了した時点でやり切った感出そうだから）

# 画面遷移でハマった
公式リファレンスを見つつ、

- 試合結果リストで新規登録をタップしたら試合結果登録の画面に遷移
- 試合結果の登録が済んだら試合結果リストの画面に戻る

ということをChatGPTさんやGeminiさんのお力を借りつつ実装。

```Kotlin:ItemListFragment
val fragment = NoteFragment().apply {
    arguments = Bundle().apply {
        putString("matchDateId", "0")
        putString("matchDate", currentDate)
        putString("matchId", "0")
    }
}

parentFragmentManager.beginTransaction()
    .replace(R.id.nav_host_fragment_activity_main, fragment)
    .addToBackStack(null)
    .commit()
```

```Kotlin:ItemFragment
val navController = findNavController()
~中略~
navController.navigate(R.id.trans_item_list)
```

としていたが、実際に動かしてみたら以下のエラーでハマりました。
```IllegalArgumentException: Navigation action/destination～cannot be found from the current destination```

mobile_navigation.xmlには
~~~xml:mobile_navigation
<action
    android:id="@+id/~~~"
    app:destination="@id/~~~"
>
</action>
~~~
と書いているし、指定しているidにタイポなどもない。
ログ出力してみたが、狙い通りのidは取れている。
なんで見つからないんだ・・・というところでハマりました。

# 動かなかった原因
本格的な画面遷移を実装するころにはすっかり忘れていた、リスト画面から登録画面に遷移するための以下の記載がマズかった。

~~~Kotlin:ItemListFragment
val fragment = NoteFragment().apply {
    arguments = Bundle().apply {
        putString("matchDateId", "0")
        putString("matchDate", currentDate)
        putString("matchId", "0")
   }
}

parentFragmentManager.beginTransaction()
    .replace(R.id.nav_host_fragment_activity_main, fragment)
    .addToBackStack(null)
    .commit()
~~~

手動でフラグメントをreplaceしてしまっているせいで、NavControllerではなくFragmentManagerに依存した遷移になっていまい、ItemFragmentがNavControllerに認識されなくなってしまっていた模様。

# 修正
## mobile_navigation
1. actionの追加
mobile_navigationでItemFragment → ItemListFragmentのactionは追加していたが、NavControllerで画面遷移を行いたいのでItemListFragment → ItemFragmentのactionも追加しなければならなかった

2. パラメータの追加
画面遷移時、パラメータを渡したいためargumentsでputStringとしていたが、AndroidStudioさんの助言によるとmobile_navigationのargumentタグで記載しなければダメとのこと。

結果、mobile_navigationを以下のようにした
~~~xml:mobile_navigation
<fragment
    android:id="@+id/navigation_item"
    android:name="XXX.ItemFragment"
    android:label="試合結果の登録画面"
    tools:layout="XXX" >
    <action
        android:id="@+id/trans_to_item_list"
        app:destination="@id/navigation_item_list">
    </action>
    <argument
        android:name="matchDateId"
        app:argType="string" />
    <argument
        android:name="matchDate"
        app:argType="string" />
    <argument
        android:name="matchId"
        app:argType="string" />
</fragment>

<fragment
    android:id="@+id/navigation_item_list"
    android:name="XXX.ItemListFragment"
    android:label="試合結果リスト"
    tools:layout="XXX">
    <action
        android:id="@+id/trans_to_item"
        app:destination="@id/navigation_item"
    />
</fragment>
~~~

## Fragment
フラグメントもNavControllerを使う方式に修正

~~~diff_Kotlin:ItemListFragment
-val fragment = NoteFragment().apply {
-    arguments = Bundle().apply {
-        putString("matchDateId", "0")
-        putString("matchDate", currentDate)
-        putString("matchId", "0")
-   }
-}

-parentFragmentManager.beginTransaction()
-    .replace(R.id.nav_host_fragment_activity_main, fragment)
-    .addToBackStack(null)
-    .commit()
                
+val action = NoteListFragmentDirections.transitionToNote(
+    matchDateId = match.matchDateId,
+    matchDate = match.matchDate,
+    matchId = match.matchId
+)
+findNavController().navigate(action)
~~~