アクションを通じて画面間の値渡しを行う
ここまでは、アクティビティにも存在していた機能の焼き直しの色合いが強かったですが、最後に、ナビゲーションアーキテクチャコンポーネントならではの機能を解説します。
前回も解説したとおり、ディスティネーションは自身が受け取りたいパラメータとして、 Arguments属性を定義することができます。この Argumentsは、フラグメントが元々持っている Arguments機構をそのまま利用しています。そのため、リスト6のように、 Arguments機構の名残が色濃く残っています。
// FirstScreenFragment.ktから送るとき
val bundle = bundleOf("initialCount" to 100)
Navigation.findNavController(v).navigate(actionId, bundle)
// SecondScreenFragment.ktで受け取るとき
val initialCount = arguments?.getInt("initialCount")
NavController#navigate()メソッドを使っていること以外は、従来のフラグメントで Argumentsを使った場合とまったく同じ使い方です。そのため、元々のよくなかったところもそのまま残っています。
フラグメントの Arguments機構のよくなかった点の1つとして、型安全でなかったことが挙げられます。パラメータのデータ型や名前をしばる仕組みが用意されていないので、送る側は本当にそのデータ型や名前で送っていいのか、受け取る側は本当にその型と名前で取り出せるのか、確証が得られないままデータのやり取りをしているのです。送り手や受け手が型や名前にささいなタイプミスをしただけで、簡単に壊れてしまい、該当の機能を動かすまで壊れたことを知ることもできないのは、恐ろしいことです。
この課題を解決するため、 Argumentsを型安全にやり取りするための仕組みとして、SafeArgs(セーフアーグス)というライブラリがナビゲーションアーキテクチャコンポーネントの一部として用意されました。この機能について解説します。
サンプルコードの「ThirdStep」プロジェクトに導入済みのコードがあるので、参考にしてください。
SafeArgsを導入する
まずは、ライブラリを導入します。Gradleのプラグインとして提供されているので、まずはappではなく、トップレベルの階層にあるbuild.gradleを編集します(リスト7)。
buildscript {
// 省略
dependencies {
classpath 'com.android.tools.build:gradle:3.3.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// ↓この行を追加する
classpath "android.arch.navigation:navigation-safe-args-gradle-plugin:1.0.0-beta02"
}
}
ここでのバージョン( 1.0.0-beta02の部分)は、 navigation-uiのライブラリを追加したときと同様に、 navigation-fragmentとバージョンを合わせます。続けて、appモジュールのbuild.gradleにも行を追加します(リスト8)。
apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' // ↓この行を追加する apply plugin: 'androidx.navigation.safeargs'
この編集が終わったら、Android Studioの右上の
のボタンを押して、ライブラリをロードします。
ディスティネーションにArgumentsを設定する
環境ができたので、次はSafeArgsを使ってみましょう。まずは、前回解説したように Argumentsを設定します(図19)。
これで、SecondScreenFragmentというディスティネーションは initialCountという int型の数値を受け取りたい意思を示すようになりました。
自動生成されたクラス
これだけだと何も起こらないので、Android Studioのビルドボタン
を押して、一度ビルドを実行します。終了したら、 generatedJavaフォルダの中をみて見てください(図20)。
ディスティネーションと似た名前が付いていますね。それぞれ、次の意味を持っています。
-
FirstScreenFragmentDirections:FirstScreenFragmentから安全にArguments付きのアクションを構築するためのクラス -
SecondScreenFragmentArgs:SecondScreenFragmentで安全にArgumentsを受け取るためのクラス
これらは、アクションを持つディスティネーションや、 Argumentsを持つディスティネーションを作ると、ビルド時に自動生成されるクラスです。自動生成される先は、元になったクラスと同じパッケージなので、インポートせずに呼び出すことができます。
自動生成クラスを用いた画面遷移
今回生成されたクラスを使うことで、リスト6の処理はリスト9のように変わります。
// FirstScreenFragment.ktから送るとき
val action = FirstScreenFragmentDirections
.actionFirstScreenFragmentToSecondScreenFragment() // (1)
action.initialCount = 1 // (2)
Navigation.findNavController(v).navigate(action)
// SecondScreenFragment.ktで受け取るとき
val initialCount = arguments?.let {
SecondScreenFragmentArgs.fromBundle(it).initialCount // (3)
}
まず、(1)ではアクションのIDがメソッドになっていることに注目してください。これを呼び出すことで、アクションのオブジェクトを生成することができます。また、(2)では initialCountプロパティへの値のセットを行っていますが、これは Argumentsに定義された型を元に作られており、コンパイル時の型チェックの対象になります。そして、受け取り側の(3)でも、 Argumentsをパースして、 initialCountをプロパティとして取り出せるようになっています。もちろんこれも型チェック可能です。
このSafeArgsの機能を使うことで、画面間の値渡しを安全に行うことができます。
まとめ
3回に分けて、Android Studioからナビゲーションアーキテクチャコンポーネントの使い方について解説しました。Android Studioがサポートする範囲のナビゲーションアーキテクチャコンポーネントは、今後、 android.arch.が androidx.になる変更が予定されています。少し時間がたってから触る場合には注意してください。
単一のアクティビティだけで画面遷移ができるようになることで、ViewModel等のライブラリを用いて、画面をまたいだ状態管理がやりやすくなるメリットが出てきます。複雑な状態を扱うアプリでは、導入を検討してみてはいかがでしょうか。
