〈kotlin〉Navigation② SafeArgs

Android studioでkotlinを使ってAndroidアプリ作成の勉強中。

画面遷移の設定に使用するNavigationコンポーネントのSafe Argsについて。
デスティネーション間を移動する際は、Safe Args Gradle プラグインの使用が推奨されている。
Safe Argsによってデスティネーション間でタイプセーフなナビゲーションと引数の受け渡しができる。

準備
//プロジェクトレベルのgradle
buildscript {
    dependencies {
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.4.1"
    }
}

//アプリレベルのgradle
plugins {
    id "androidx.navigation.safeargs.kotlin"
}

Safe Argsを使用した画面遷移の設定

ナビゲーショングラフ

例としてfirstFragmentからsecondFragmentへ遷移するナビゲーショングラフを以下のように定義する。

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/firstFragment">

    <fragment
        android:id="@+id/firstFragment"
        android:name="com.example.sampleApp.firstFragment"
        android:label="fragment_first"
        tools:layout="@layout/fragment_first" >
        <action
            android:id="@+id/action_firstFragment_to_secondFragment"
            app:destination="@id/secondFragment" />
    </fragment>
    <fragment
        android:id="@+id/secondFragment"
        ...
    </fragment>
</navigation>
Safe Argsによって作成されるクラスとメソッド

Safe Argsが有効になっていると、
アクションの発生元となる送信側デスティネーションごとにクラスとメソッドを自動生成する。
(生成されていなければRebuildする。)
上記のナビゲーショングラフ(firstFragment→secondFragment)では
送信側のfragment名を使用してFirstFragmentDirectionsクラスが生成され、
その中にactionFirstFragmentToSecondFragment()メソッドを持つ。
このメソッドはNavDirections オブジェクトを返し、
NavDirections オブジェクトはnavigate()メソッドに直接渡すことができる。

画面遷移

actionにNavDirectionsオブジェクトを取得し、navigate()メソッドに渡すことで画面遷移を設定できる。

binding.button.setOnClickListener{
    val action = FirstFragmentDirections.actionFirstFragmentToSecondFragment()
    this.findNavController().navigate(action)
}

Safe Argsを使用した引数の受け渡し

ナビゲーショングラフ

例としてfirstFragmentからsecondFragmentに遷移する際、
String型の変数dataを受け渡すことにする。
受け渡す引数は受け取り側のFragmentのargumentタグに定義する。

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/firstFragment">

    <fragment
        android:id="@+id/firstFragment"
        android:name="com.example.sampleApp.firstFragment"
        android:label="fragment_first"
        tools:layout="@layout/fragment_first" >
        <action
            android:id="@+id/action_firstFragment_to_secondFragment"
            app:destination="@id/secondFragment" />
    </fragment>
    <fragment
        android:id="@+id/secondFragment"
        ...
        <argument
            android:name="data"
            app:argType="string"/>
    </fragment>
</navigation>

SecondFragmentにargumentを設定すると、
SecondFragmentArgsというクラスが生成される。

送信側

FirstFragment側のactionFirstFragmentToSecondFragment()の引数に渡すデータを入れる。

val sampleData = "sample"
binding.button.setOnClickListener{
    val action = FirstFragmentDirections.actionFirstFragmentToSecondFragment(sampleData)
    this.findNavController().navigate(action)
}
受信側

SecondFragmentでは、by navArgs()プロパティデリゲートを使用して引数にアクセスする。

val args: SecondFragmentArgs by navArgs()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    val tv: TextView = view.findViewById(R.id.textView)
    val sampleData = args.data
    //ナビゲーショングラフに記述したargument nameを使用してアクセス
    //args.dataにFirstFragmentで渡したsampleDataが格納されている
    tv.text = sampleData.toString()
}

参考
https://developer.android.com/guide/navigation/navigation-getting-started?hl=ja#ensure_type-safety_by_using_safe_args

https://developer.android.com/guide/navigation/navigation-pass-data?hl=ja#Safe-args