さつきのつきあたり

やってみたことをそのままメモするところ

What's Android Jetpack: Navigation

Google I/O 2018のkeynoteで発表されたAndroid Jetpackの1機能であるNavigationについて調べました。

CA.apk #6で発表したときの資料

大体はGoogle I/O報告会でLTした際のスライドにまとまっているので、こちらをどうぞ。

いくつか気になった(気になってた)ことについて

このスライドに載せられなかったけど気になっている部分などを、少し書いておきたいと思います。

特殊な表示条件の画面の対応はどうするのか

スプラッシュスクリーンのように起動時だけ表示させておきたい画面だったり、ログインが必要な場合は最初にログイン画面に遷移させたい、というような状況ってよくあると思います。

LTでは紹介できなかったのですが、ドキュメントにはこれらの画面の取り扱いについて説明があります。

https://developer.android.com/topic/libraries/architecture/navigation/navigation-conditionaldeveloper.android.com

Conditional navigation、条件付きナビゲーションだそうです。

具体的な実装方法が明記されてないのでまだ試せていないですが、特定条件下で遷移するnavigation graphを別途実装してそちらへ飛ばすみたいな感じになるんでしょうか。 条件付きといいつつ、現状は自分で状態評価して必要なら別画面に飛ばすとなるとちょっと面倒?

スプラッシュ画面に至っては下手すると一瞬Starting Destinationの画面が見えてしまうという残念な感じに… 今後に期待しておきたいと思います。

Deep Linkでアプリを起動した時の戻り先 is どこ?問題

スライド中でも説明していますが、Principle of Navigationの1つにDeep Linkによる遷移と通常操作での遷移は同一のスタックが生成する必要がある、という項目があります。

developer.android.com

この原則に従うのであれば、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の扱いどうすんの問題

このように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で表示されていた項目は表示されなくなりました。

f:id:satsukies:20180525114006g:plain

右上のカートボタンが、MainFragment側で定義されていたmenu項目です。 Toolbar自体はActivity自体にもたせているが、表示される項目をFragmentごとに指定できるみたいなので、結果アニメーションも含めていい感じになっているように見えます。解決かな?

multi moduleにした場合

Navigationでは、遷移先として以下が指定できます。

  • Fragment
  • Activity
  • Navigation Graph

Multi moduleの場合、各moduleにはエントリーポイントとなるActivityがいるのかな?と思うので、そこへのActionを定義することで画面遷移を追加できる気がしています。もしくは、別のmoduleに含まれるnavigation graphへの遷移でもいいかもしれないです。

これは別途検証したいなと思ってます。

まとめ

Navigationと上手に付き合えると、画面遷移を楽に実装できそう。Good-bye Fragment Transaction 👋 一方で、既存の構成だと場合によっては大規模なマイグレーションが必要なので、pros&consをちゃんと理解した上で入れたいですね。