LoginSignup
8
4

More than 5 years have passed since last update.

NavigationのDeepLinkのライフサイクルを調べる

Posted at

注意

こちらはnavigationのpreview版時点での話です。リリース版では挙動が異なる可能性があるので信じないでください。

はじめに

GoogleIO2018で発表されたNavigation

FragmentTransactionなどの煩わしい処理を無くし、GUIで直感的に画面遷移を実現できるAAC(Android Architecture Components)の新しいパーツです。

画面遷移はもちろんのこと、BottomNavigationNavigationViewなども簡略化のサポートを行っている優れもの。

今回はその中でも、DeepLinkの挙動が気になったので軽く調べてみました。

DeepLinkのライフサイクル

DeepLinkを実装する際に、よく考えるのは、着地した画面からback keyを押したときの挙動を考えることが多いと思います。

詳細画面に着地したあと、back key押下でアプリホーム画面に戻らなきゃいけないとかいう、あれです。

これを実現する為に、わざわざホーム画面でschemeを受け取り、URLパターンに応じて詳細画面に遷移する・・・というような実装をする必要があり(あくまで一例です。1Activity×N個Fragmentとかだと今回考える必要ない)、面倒です。

こんな煩わしさを解消してくれるツールが今回のNavigationで、直接遷移したいFragment(Activity)に 対象のURLを登録するだけで、もちろんその画面に遷移することはもちろん、それまでのバックスタックもすべて積み上がった状態で遷移を実現してくれます。

画面スタックを自作する実装が不要となるのでとても便利です。

しかし、そこで感じたのは、「表示されないスタックされた画面って、ライフサイクルどうなるの??」

実際の利用シーンで、それぞれの画面のonResumeなどにGAのScreenTrackを行っている方はたくさんいらっしゃると思います。

もし仮にすべてのスタックされた画面のライフサイクルが呼ばれてしまうと、詳細画面に遷移しただけなのに、なぜかホーム画面のScreen数も計測されてる?みたいなことが起きてしまいます。

今回はそんな事故が起きないように実際に以下のようなサンプルを作って検証してみました。

検証

まずはサンプルを作ります。Navigationは理解するのが割とかんたんだったので、詳しい内容知りたい方は先にNavigation Codelabを1度やってみるのをおすすめします。

今回作ったサンプルのnavigationはこんな感じです。

main_navigation.xml
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    app:startDestination="@id/fragment_main">

    <fragment
        android:id="@+id/fragment_main"
        android:name="com.pag.n_satou.navigationsample.MainFragment"
        tools:layout="@layout/fragment_main"
        android:label="MainFragment" >
        <action
            android:id="@+id/action_fragment_main_to_secondFragment"
            app:destination="@id/secondFragment" />
    </fragment>
    <fragment
        android:id="@+id/secondFragment"
        android:name="com.pag.n_satou.navigationsample.SecondFragment"
        android:label="SecondFragment"
        tools:layout="@layout/fragment_second">
    </fragment>
</navigation>

スクリーンショット 2018-06-03 12.28.22.png

また、fragment_mainのボタンをタップしたらsecondFragmentへ遷移するようにnavigationを設定しておきます。

MainFragment.kt
view.findViewById<Button>(R.id.button).setOnClickListener {
    findNavController(it).navigate(R.id.action_fragment_main_to_secondFragment)
}

これで、SecondFragmentはMainFragmentをスタックに持ったNavigationになりました。

また、DeepLinkをつける為にSecondFragmentにdeeplink tagをつけます

main_navigation.xml
<fragment
    android:id="@+id/secondFragment"
    android:name="com.pag.n_satou.navigationsample.SecondFragment"
    android:label="SecondFragment"
    tools:layout="@layout/fragment_second">
    <deepLink app:uri="www.navigationsample.com/foo"/>    // ココ
</fragment>

AndroidManifestも編集します。

AndroidManifest.xml
<activity android:name=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <nav-graph android:value="@navigation/main_navigation"/>    // ココ
</activity>

これでSecondFragmentに直接deeplink遷移するnavigationのできあがりです。

ライフサイクルを見てみる

まずは起動→ボタンタップ→画面遷移の順でライフサイクルを確認します

通常時

// アプリ起動
D/com.pag.n_satou.navigationsample.MainActivity   #onCreate
D/com.pag.n_satou.navigationsample.MainFragment   #onCreateView
D/com.pag.n_satou.navigationsample.MainFragment   #onViewCreated
D/com.pag.n_satou.navigationsample.MainFragment   #onStart
D/com.pag.n_satou.navigationsample.MainActivity   #onResume
D/com.pag.n_satou.navigationsample.MainFragment   #onResume

// ボタンタップ→画面遷移
D/com.pag.n_satou.navigationsample.SecondFragment #onCreateView
D/com.pag.n_satou.navigationsample.SecondFragment #onViewCreated
D/com.pag.n_satou.navigationsample.SecondFragment #onStart
D/com.pag.n_satou.navigationsample.SecondFragment #onResume

いつもどおりのライフサイクルです。では、deeplink時のライフサイクルを見てみます。

DeepLink時

// DeepLinkで起動
D/com.pag.n_satou.navigationsample.MainActivity   #onCreate
D/com.pag.n_satou.navigationsample.MainActivity   #onCreate
D/com.pag.n_satou.navigationsample.SecondFragment #onCreateView
D/com.pag.n_satou.navigationsample.SecondFragment #onViewCreated
D/com.pag.n_satou.navigationsample.SecondFragment #onStart
D/com.pag.n_satou.navigationsample.MainActivity   #onResume
D/com.pag.n_satou.navigationsample.SecondFragment #onResume

// バックキーでMainFragmentへもどる
D/com.pag.n_satou.navigationsample.MainFragment   #onCreateView
D/com.pag.n_satou.navigationsample.MainFragment   #onViewCreated
D/com.pag.n_satou.navigationsample.MainFragment   #onStart
D/com.pag.n_satou.navigationsample.MainFragment   #onResume

親のActivity/対象のFragmentだけが初期化され、初めてスタックされた画面に遷移したときに画面が初期化されるようです。ヨカッター。

まとめ

対象の画面にたどり着いたときだけライフサイクル・初期化が行われます。

まだ正式版ではないのでリリース版で挙動が変更されるかもしれませんが、Android開発においてライフサイクルは心臓部ぐらいの重要度だと思うので、これからも気をつけてみていきたいと思います。

8
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
4