1児のパパ兼Android開発者

kiuchi氏:最初に名前を書いたからトップバッターになったというkiuchiです。びっくりしました。一番最後に申し込んだはずなのにトップバッターって「あれ!?」みたいな感じでしたね。

トップバッターってこの場が温まっていないというきつい環境でやらざるをえないので、ちょっとみなさんテンション上げていただけたらなと思います。

(会場拍手)

ありがとうございます! では軽く自己紹介を。すでにshibuya.apk24回目やDroidKaigiでも1回発表しているので、ひょっとしたら僕の顔見たことある人がいると思いますが、一応自己紹介します。

職業は1児のパパ兼Android開発者です。Androidのほうが兼業ですね。1児のパパがメインです。一応、趣味で「らくでん」というAndroidアプリを作っていたりします。

「明日の自分に優しいコードを書く」ということをモットーに毎日コーディングしてたりします。Twitterもやっています。

説明し忘れましたが、今日の発表でお見せするサンプルコードはGitHubのところにあるので、もしよろしければお手元で「https://github.com/kiuchikeisuke/NavigationSandbox」と打っていただければと思います。

では、軽く最近のアクティビティを。Gmailに来るconnpassの通知をいい感じにSlackに通知するというものを作りました。

一応Qiitaに投稿しているので気になった人は見てください。今日の通知もこれで来ているので、便利で自分作って満足しています。

まぁ、こういうのはサブです。重要なのは、ムスメが立ちました。大地に立ちました!

(会場拍手)

立って、もうめっちゃ歩くんですよね。僕が遠くへ行ったらドドドドッって突撃してきて、「ちょっと会社行くんだけど……」って言ったら大泣きするという、そういう状況です。そんな感じで育児パパをやっております。よし、十分場が温まったかな。

NavigationのNavOptions周りを覗いてみよう

では、今日のお話はNavigationについてです。これに関して、みなさんご存じのとおりまだVersion1.0.0-alpha02になっています。なので、今後大きく変わる可能性があるので、ここで発表したから「よし使えるぞ!」とはならないのでご注意ください。

というのと、もう1つ、「Navigationとはなんぞや?」という話は、申し訳ありませんが時間の都合上カットしております。なので、みなさんNavigationご存じだと思いますが、その前提でお話しさせていただきます。

では、ちょっと僕の興味本位で聞きたいんですけれども、Navigation、サンプルソースコードでいいので、ちょっと書いてみたという方ってどれぐらいいます?

(会場挙手)

半分くらいですかね。あ、でも、6割ぐらいですかね。ありがとうございます。

ちなみにそれで、実際の会社のプロジェクトでもいいし個人のプロジェクトでもいいですが、実際に導入してみたという方はいらっしゃいますか? あ、やっぱり0ですね。みなさん二の足を踏んでいるという感じですね。

僕もそんな感じでやっています。僕も個人でさっきの「らくでん」というやつに取り込もうかと思ったんですが、怖くてまだやっていません。alphaが取れたら導入したいなと思っています。

そんな感じなんですけれども、前もって予習というかたちでNavigationを見ていこうかなと思います。

さっそくなんですけれども、非常にシンプルな「ボタンを押したら、画面が切り替わる、アクティビティが切り替わる」というNavigationの実装です。

Beforeは今までどおり、Intentを生成してstartActivityするというコーディングです。Afterのほうは、今回のNavigationというものを使ってみた、おそらく一番シンプルな感じでコーディングしたやつです。たぶん一番シンプルだと思います。

idのところで遷移したいActivityを指定してあげて、ボタンを押したら切り替わるというふうな、ここでちょっと目障りな感じで動いていますけど、ボタンを押したら動くという簡単なコーディングになっています。

たぶんちょっと書いてみたことがある人だと「なるほどね。確かにこうなるね」と思っていただけるかなと思いますが、それではみなさん、上のほうを見てください。これの場合どうしましょう。

なにが変わっているかというと、起動のフラグを設定した場合ですね。「SINGLE_TOPのフラグを設定した場合、はて、どうやって書くんだ?」というのを僕も気になって調べたんですが、なんか情報がないぞと。それで自分でいろいろ調べてどんな動きになっているのか調べました。

その結論として、今回の発表のネタであるNavOptionsがここで使われるようになります。

これでAfterのほうを見ていただければわかるんですが、setLaunchSingleTop(true)。おそらくこのメソッド名だけでなにをしてくれるのかわかると思いますが、このフラグを設定することで、上記で書いてあるFLAG_ACTIVITY_SINGLE_TOPのフラグの設定をしたものと同等の動きになります。

ちょっとアップデートします。NavOptions.Builder().setLaunchSingleTop(true).build()。

NavOptions イズ 誰? Who is 誰?

NavOptionsとは何か?

公式のやつを引っ張ってきました。

説明は非常にシンプルで、NavOptions stores special options for navigate actions。まぁ、Navigationにちょっとスペシャルなオプションを設定できますよ、というのがこいつなわけです。こいつでざっくりなにができるかを僕なりに簡単にまとめました。

まず、そもそもこいつはなんぞやというところで、Navigationのオプションを諸々設定できるクラスとなっております。主にできることが、起動時のフラグを設定でき、起動のアニメーションもこれで設定できます。もう1つ、Back Stackから復帰のアニメーションもこれで設定できます。

あっ、すいません。一番下のカテゴリがぜんぜん違いますね。今回はFragmentからActivityのコードしか書いてなくて、FragmentからFragmentへの遷移はどうなっているのか、今回は話さないので、気になる方はご自分で調べていただければと思います。

なので、今回のメインのお話は上2つの、起動時のフラグを設定するという動作と、起動時のアニメーションを設定するときにどんな動きになっているかを見ていこうと思います。

ちなみに、ちょっと実機で動かそうかなと思ったんですが、僕はチキンなので全部スライドに起こしました。一応裏では動いているんですけどね。たぶん失敗するかなと思って。

起動時のフラグの設定

では、起動時のフラグの設定はどうなっているかですね。

これは先ほど映したものです。

注目していただきたいのはval optionsです。このsetLaunchSingleTopのところが鍵になっているので、こいつがなにをやっているのか、ちょっと中身を見てみましょう。

こいつがここに書いてあるとおり、setLaunchSingleTopを取っています。

中身をよくよく見ると、true or falseでmLaunchModeというものにパラメータ設定しています。これは論理演算子なので、普通に考えてtrueになっていたらこのフラグが設定されて、falseの場合が設定が外されるんだなと。

なので、このmLaunchModeというものがたぶんどこかで参照されて、intent起動のときになにか設定されるんじゃないかという予想が立ちます。

ブレークポイントを挟んでみたらどうなるか?

では実際に、このソースコードを実際にビルドしてブレークポイント挟んでみてみたらどうなるのか見ていきましょう。

一番最初に呼ばれるのはこのnavigateという関数です。なので、これがどこに行くかというと、このNavControllerにデータが飛んできます。そこでどんどん処理が進んでいきます。

もし手元にAndroid Studioを起動できる方がいたら、起動して辿ってみるとおもしろいかなと思います。

これは実際にブレークポイントで挟んでいるときの動きです。これがどうなっていくかというと、どんどん値を取ってきます。navActionというものが取っているようです。

そこからさらにどうなっていくかというと、さらにその中に入っていって、先ほどのnavActionが!= nullなので、この中に入ります。

このdestIdというものをどうやら取ってきているようだと。

これをなにから取ってくる……navActionのgetDestinationId。Destinationは「先」という直訳になってくるので、おそらく遷移先のなんらかのIDを取ってきているんだろうというおおよその予想が立ちます。

さらにこの先へ進んでいくと、destIdが入っています。

値が入っているので、今フォーカスされているif文のところには、一番最初の条件で弾かれるので、ここにはどうやら入りません。

さらにどうやっていくのか。このdestIdからさらに処理を見ていくと、findDestinationというものがどうやら呼ばれるようです。

findDestination。おそらく遷移先を取ってきているんじゃないかなと、ここでおよその予想が立ちます。

それがNavDestination。おそらく遷移先の諸々の情報を持っているんじゃないかなとここで予想が立ちます。

それがどうも最後にnodeのnavigateのargs、さっきのnavOptionsと。これがnodeという変数に格納されて、そのnavigateの中にいきます。

注目しておきたいのは、nodeの実体がどうやらActivityNavigatorというものになっているようだと。ここがポイントです。

そもそも、nodeのnavigateってなんなんだと。これを見てもらえると、どうやら単純にmNavigatorのnavigateを呼んでいるようです。

このmNavigatorは何者なのか見てみると、先ほど出てきたActivityNavigator、名前からしてたぶんActivity関係の遷移を司っているクラスなんだろうなという予想が立つかなと思います。

では、この実体であるActivityNavigatorをちょっと見ていこうと思います。実際、どこに来るかというと、先ほどのnavigateという関数のところに来ます。

そうすると、おっと、いきなりIntentが出てきました。一気になにをするか見えてくるような気がしますね。ここでおそらくもう少し先でstartActivityが呼ばれるんじゃないかと思われます。

これ「?」マークがついてますが、「いきなりどこから取ってきてんだ?」という感じですね。このまま処理を読んでいくと、このshouldLaunchSingleTopのメソッドが見えますね。

そしてその中に入っています。よく見ると、addFlagsでまさに今回セットしたかったFLAG_ACTIVITY_SINGLE_TOPのパラメータがセットされています。

これによってSINGLE_TOPのフラグがセットされます。さらにもう少し進めていくとstartActivityしています。

これでActivityが起動されるという流れになっております。

なので、さっきのnavOptionsのパラメータをセットすると、巡り巡ってここでパラメータがセットされるというふうな動きになっています、というかたちですね。

ちなみに、この呼んでいるintentなんですが、どこでセットされているかというと、ActivityNavigatorのDestination setComponentNameで動いています。

これ、ブレークポイントを挟んでアプリを起動してもらうと、アプリ起動時にここが呼ばれます。この名前が引かれるのが、xmlで設定した名前がここで引かれるので、対応するActivityがここでセットされるというわけです。

まとめと注意点

ちなみに、これに以外にいくつかフラグがありますが、どうなっているかというと、なんと非推奨になっています。

びっくりですね。だからSingleTopだけが有効になってて、「おおっ!?」ってなります(笑)。

非推奨になったコメントを見てみると、setLaunchDocumentに関しては「Manifestのattrで設定してね」と軽く書いてあります。setClearTaskに関しては「setPopUpTo〜を使ってね! inclusiveのフラグはtrueでよろしく!」と書いてあります。

ちなみにアニメーションのほうはサクッと終わります。なので、今使うのはちょっと怖いです。このあとどうなるかわからないです。

起動時のアニメーションです。

どうなっているかというと、setEnterAnimとsetExitAnimというかたちでセットしています。これも上のほうのコードはoverridePendingTransitionにぶち込んでいます。よくあるやつです。

そしてどうなっているのかsetEnterAnim〜を見てみると、EnterAnimとExitAnimにパラメータをセットしているだけですね。ただのセッターです。

こいつはどこで使われているか? 実はさっきのコードの中でちらっと出てきます。この丸ついているところです。

よーく見てみるとそのパラメータを参照してますね。

その中で、overridePendingTransition(enterAnime〜)にデータがぶち込まれているというかたちなっています。

なので、ここでHostActivity、つまり遷移元の画面からパラメータを、元のActivityにパラメータをセットして呼んでいるので、NavOptionsに設定すると巡り巡ってここでアニメーションができるという流れになっております。

まとめです。Activityの起動に関しては、FLAG指定は一部はNavOptionsでできます。ただ、ほかのものに関しては、今、どうなるかはこの先わからないです。Activity遷移時のアニメーションもNavOptionsでできます。

ただ、先ほどもちょっと見ていただけたと思うんですけど、非推奨メソッドも混ぜていたりするので、今後、alpha版からβ版、正式版になったときどうなるかはわかりません。そこは取り扱い注意となっております。以上です。

ちなみに前々回の際にも出しましたが、一応投げ銭のコードとかを貼ってたりします。

(会場笑)

ちなみに、Sandboxのさっきページを見ていただけると下のほうに投げ銭コードが、これとまったく同じのが出てきます。前々回では2人の方からサンキューをもらいました。ありがとうございます。

ちょうど時間ですかね。以上です。ありがとうございました。

(会場拍手)