What's Android Jetpack: Navigation
Google I/O 2018のkeynoteで発表されたAndroid Jetpackの1機能であるNavigationについて調べました。
CA.apk #6で発表したときの資料
大体はGoogle I/O報告会でLTした際のスライドにまとまっているので、こちらをどうぞ。
いくつか気になった(気になってた)ことについて
このスライドに載せられなかったけど気になっている部分などを、少し書いておきたいと思います。
特殊な表示条件の画面の対応はどうするのか
スプラッシュスクリーンのように起動時だけ表示させておきたい画面だったり、ログインが必要な場合は最初にログイン画面に遷移させたい、というような状況ってよくあると思います。
スプラッシュスクリーンはどうするのがいいんだろ#ca_apk #ca_aab #io18jp
— なっぴー🍼 (@napplecomputer) 2018年5月22日
LTでは紹介できなかったのですが、ドキュメントにはこれらの画面の取り扱いについて説明があります。
https://developer.android.com/topic/libraries/architecture/navigation/navigation-conditionaldeveloper.android.com
Conditional navigation、条件付きナビゲーションだそうです。
具体的な実装方法が明記されてないのでまだ試せていないですが、特定条件下で遷移するnavigation graphを別途実装してそちらへ飛ばすみたいな感じになるんでしょうか。 条件付きといいつつ、現状は自分で状態評価して必要なら別画面に飛ばすとなるとちょっと面倒?
スプラッシュ画面に至っては下手すると一瞬Starting Destinationの画面が見えてしまうという残念な感じに… 今後に期待しておきたいと思います。
Deep Linkでアプリを起動した時の戻り先 is どこ?問題
ディープリンクで遷移した時の「戻る」ボタンは前に起動していたアプリに戻るのではなく、遷移先の画面の親画面に遷移する
— akatsuki174 (@akatsuki174) 2018年5月22日
なるほどそうゆう動きになるのか #ca_aab #ca_apk #io18jp
DeepLink時のUpキー動作原則破ってるの作ってるなあ… #ca_aab #ca_apk #io18jp
— k_shinn (@k_shinn) 2018年5月22日
deeplinkで画面立ち上げたときにバックキーがアップキーと同じ挙動するのはいいことなの…? #ca_apk
— 山田航空 (@yamacraft) 2018年5月22日
ユーザーがdeeplinkに期待することは最適な形でコンテンツを閲覧することにあってアプリを立ち上げることではないし、なにより同じ挙動ならアップキーいらないのでは…ってなりますね…
— 山田航空 (@yamacraft) 2018年5月22日
スライド中でも説明していますが、Principle of Navigationの1つにDeep Linkによる遷移と通常操作での遷移は同一のスタックが生成する必要がある、という項目があります。
この原則に従うのであれば、Deep Linkで起動した画面がStarting Destinationでない限りは、通常操作で当該画面まで遷移した場合と同じスタックが生成されなくてはいけないということになります。 結果的に、自身のアプリ内でのBackキーやUpボタンの挙動は、画面への遷移手段に関わらず一定となるはずです。
さらに、Principle of Navigationには「Upはアプリを終了させることはない」「BakcとUpはアプリ内で同等な操作となる」という原則が書かれていて、これらを考慮するとDeep Linkでのアプリ起動時だとしてもBackキーで元のアプリへ戻る挙動は、"Principle of Navigation"的には間違い、と解釈できると思います。
ただ一方で、Google PlayアプリやGoogle MapアプリのようなGoogle謹製アプリをはじめ、多くのアプリは違う挙動を示しているので、この原則が本当に正しいのかはまだ 🤔という感じです。 ちなみにAbemaTVはブラウザのURL踏んだ際の起動でも、Backキー押下で親画面に戻る挙動になっていました。
いずれにせよ、こちらについても今後の動向を見守る必要がありそうです。
Toolbarの扱いどうすんの問題
Navigationの時のToolbarの扱いどうしよっかっていう知見をそろそろ誰かやってないかな。 #ca_apk
— Daichi Furiya (Wasabeef) 🐾 (@wasabeef_jp) 2018年5月22日
このようにwasabeefさんが言っています。これはGoogle I/O現地で一緒に行動していた方も同じ疑問を持っていました。 Single Activityなアプリにする場合で、各面でToolbarに出したいものが異なる場合どうするのか、ということです。 ToolbarはActivityが持っていることが多い?と思うのですが、一方で表示するFragmentごとにToolbarの表示内容を調整したいという気持ちになるので、どっちに持たせるの?という疑問。
これの答え?を探してみました。
Codelabのコードを見ていると、Navigationでの遷移対象となっているFragment側で onCreateOptionsMenu()
をオーバーライドして、画面固有のメニューを生成しています。例えば、MainFragment.ktでは以下のような感じになってます。
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { inflater?.inflate(R.menu.main_menu, menu) }
一方で、遷移先のFlowStepFragment.ktでは上のような記述はない状態です。
menu/main_menu.xmlは以下のような感じです。
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/main_2" android:icon="@drawable/ic_shopping_cart_white" android:title="@string/shopping_cart" app:showAsAction="ifRoom" /> </menu>
この状態で実機へdeployしてみると、MainFragmentが表示されている状態ではmain_menuに定義されている項目がToolbarに表示され、FlowStepFragmentへ遷移するとMainFragmentで表示されていた項目は表示されなくなりました。
右上のカートボタンが、MainFragment側で定義されていたmenu項目です。 Toolbar自体はActivity自体にもたせているが、表示される項目をFragmentごとに指定できるみたいなので、結果アニメーションも含めていい感じになっているように見えます。解決かな?
multi moduleにした場合
機能別にmulti moduleにした時もNavigationはいい感じにつかえるのだろうか?#ca_apk
— atsumo (@atsumo) 2018年5月22日
Navigationでは、遷移先として以下が指定できます。
- Fragment
- Activity
- Navigation Graph
Multi moduleの場合、各moduleにはエントリーポイントとなるActivityがいるのかな?と思うので、そこへのActionを定義することで画面遷移を追加できる気がしています。もしくは、別のmoduleに含まれるnavigation graphへの遷移でもいいかもしれないです。
これは別途検証したいなと思ってます。
まとめ
Navigationと上手に付き合えると、画面遷移を楽に実装できそう。Good-bye Fragment Transaction
👋
一方で、既存の構成だと場合によっては大規模なマイグレーションが必要なので、pros&consをちゃんと理解した上で入れたいですね。