Save 37% off PRO during our Black Friday Sale! »

Navigation Componentのデータ受け渡しのつまづき

4c0c2a5a353b06c9d0238373872822bb?s=47 Suyama
February 12, 2020

Navigation Componentのデータ受け渡しのつまづき

概要:Android Jetpack Navigationコンポーネントの複雑な画面遷移を実装方法
背景:プロダクトコードの一部にNavigationを導入

目的:NavigationでNestedGraphを用いた場合のデータ受け渡し方法

4c0c2a5a353b06c9d0238373872822bb?s=128

Suyama

February 12, 2020
Tweet

Transcript

  1. Navigation Componentの データ受け渡しのつまづき potatotips #68(2020/02/12) Suyama 1

  2. ⾃⼰紹介 Name  :Suyama Company :Studyplus Inc. Role   :Android Engineer • potatotips参加2回⽬

    • DroidKaigi2020に登壇予定 2
  3. ⽬的 背景 • StudyplusアプリにNavigationを導⼊ 伝えたいこと • Navigationの導⼊は簡単だったこと • 複雑な画⾯構造でのデータ受け渡し⽅法 3

  4. Navigationの簡単な説明 4

  5. Navigationとは • Jetpack Componentの⼀つ • Fragment遷移を簡単に実装可能 • Navigation EditorでGUI操作 NavGraph

    5
  6. データ受け渡し 6

  7. Argumentの設定 データ受け渡しはNavGraphで実装可能 • プリミティブ型 • Parcelable • Serializable • Enumなど

    7
  8. 8 // nav_graph.xml <fragment android:id="@+id/secondFragment" android:name="com.example.navigationsample.SecondFragment"> // ࣗಈੜ੒ <argument android:name="hogeName"

    app:argType="string" android:defaultValue="hoge" /> </fragment>
  9. SafeArgsの利⽤ SafeArgsのプラグインを適⽤することで DirectionsクラスとArgsクラスが⾃動⽣成 • Directions:遷移する関数の引数でArgument を型安全に設定可能 • Args:by navArgs()で型安全に取得可能 9

  10. // DirectionsΫϥε(ࣗಈੜ੒) class FirstFragmentDirections private constructor() { private data class

    ActionFirstToSecond( val hogeName: String = "hoge" ) : NavDirections { override fun getActionId(): Int = R.id.action_first_to_second override fun getArguments(): Bundle { val result = Bundle() result.putString("hogeName", this.hogeName) return result } } companion object { fun actionFirstToSecond(hogeName: String = "hoge"): NavDirections = ActionFirstToSecond(hogeName) } } 10
  11. // ArgsΫϥε(ࣗಈੜ੒) data class SecondFragmentArgs(val hogeName: String = "hoge") :

    NavArgs { fun toBundle(): Bundle { val result = Bundle() result.putString("hogeName", this.hogeName) return result } companion object { @JvmStatic fun fromBundle(bundle: Bundle): SecondFragmentArgs { bundle.setClassLoader(SecondFragmentArgs::class.java.classLoader) val __hogeName : String? if (bundle.containsKey("hogeName")) { __hogeName = bundle.getString("hogeName") if (__hogeName == null) { throw IllegalArgumentException("Argument \"hogeName\" is marked as non-null but was passed a null value.") } } else { __hogeName = "hoge" } return SecondFragmentArgs(__hogeName) } } } 11
  12. データ受け渡しのつまづき 12

  13. Nested Graphでのデータ受け渡し NestedGraphとは • NavGraphを分けてNavGraph内で他の NavGraphを呼び出すこと つまづき • Nestされている⽅の引数が認識されない 13

  14. 14 // top_nav_graph.xml <fragment android:id="@+id/firstFragment" android:name="com.example.navigationsample.FirstFragment"> <action android:id="@+id/action_to_second" app:destination=“@id/nested_nav_graph" />

    </fragment> <include app:graph=“@navigation/nested_nav_graph“ />
  15. 15 // FirstFragment private fun navigateToSecond(hogeName: String) { findNavController().navigate( FirstFragmentDirections.actionToSecond(hogeName

    = hogeName) // Τϥʔൃੜ ) }
  16. 16 // DirectionsΫϥε(ࣗಈੜ੒) class FirstFragmentDirections private constructor() { companion object

    { fun actionFirstToSecond(): NavDirections = ActionOnlyNavDirections(R.id.action_to_second) } }
  17. 解決策 17

  18. 解決策 • Nested Graphを呼び出す側のactionタグに argumentタグを追加 • リビルドでDirectionsを再⽣成すると引数と して認識 18

  19. 19 // top_nav_graph.xml <fragment android:id="@+id/firstFragment" android:name="com.example.navigationsample.FirstFragment"> <action android:id="@+id/action_to_second" app:destination="@id/nested_nav_graph"> //

    ௥Ճ͢Δ͜ͱͰDirectionsͷҾ਺ͱͯ͠ೝࣝ <argument android:name="hogeName" app:argType="string" android:defaultValue="hoge" /> </action> </fragment> <include app:graph=“@navigation/nested_nav_graph“ />
  20. 20 // DirectionsΫϥε(ࣗಈੜ੒) class FirstFragmentDirections private constructor() { private data

    class ActionFirstToSecond( val hogeName: String = "hoge" ) : NavDirections { override fun getActionId(): Int = R.id.action_to_second override fun getArguments(): Bundle { val result = Bundle() result.putString("hogeName", this.hogeName) return result } } companion object { fun actionFirstToSecond(hogeName: String = "hoge"): NavDirections = ActionFirstToSecond(hogeName) } }
  21. 21 // FirstFragment private fun navigateToSecond(hogeName: String) { findNavController().navigate( FirstFragmentDirections.actionToSecond(hogeName

    = hogeName) ) }
  22. まとめ • NavigationではSafeArgsのプラグインを⼊れる ことで型安全、null安全でデータ受け渡し可能 • Nested Graphを⽤いる場合、actionタグに argumentタグを追加することで解決する 22