略解 The Navigation Architecture Component

Bbf2a0e77c98104ac16ef6d0098c1385?s=47 yagi2
June 07, 2018

略解 The Navigation Architecture Component

2018/06/07 umeda.apk #4 LT
https://shibuya-apk.connpass.com/event/88738

Links
>> yagi2/Android-Navigation-Sample: The Navigation Architecture Component Sample App https://github.com/yagi2/Android-Navigation-Sample #NowBrowsing

【Android】Google IO 2018で新発表された navigation についての詳細レポート - DMM inside » https://inside.dmm.com/entry/2018/05/25/android-navigation

Navigation Component // Speaker Deck » https://speakerdeck.com/satsukies/navigation-component

Bbf2a0e77c98104ac16ef6d0098c1385?s=128

yagi2

June 07, 2018
Tweet

Transcript

  1. ུղ The Navigation Architecture Component 2018/06/07 umeda.apk #4 γʔαʔגࣜձࣾ Itsuki

    Aoyagi (@yagi2)
  2. ࣗݾ঺հ ɾ੨༄ थʢItsuki Aoyagiʣ ɾ΍͗ʹ͍ʢ@yagi2, @yaginierʣ ɾγʔαʔגࣜձࣾ ɾAndroidΞϓϦΤϯδχΞ ɹɹɹɹɹˡ ΞΠίϯɹɹɹɹɹɹຊମ

  3. Navigation Component ɾAndroid Jetpackͷ1ػೳͱͯ͠৽͘͠ఏڙ͞Εͨ ɾը໘ભҠΛ؆୯ʹ࣮૷Ͱ͖ΔΑ͏ʹͳΔ ɾGoogle I/O 2018ͷDeveloper KeynoteͰ ɹʮStoryboardʂʁʯͬͯͳͬͨ͋Ε΋ͦΕͷΤσΟλ

  4. None
  5. ͲΜͳ΋Μʁ ɾStoryboardͷը໘ભҠ͚ͩΛൈ͖ग़ͨ͠ײ͡ ɹɾActivity/FragmentؒͷભҠ΍DeepLinkͰͷىಈ ɹɾSafeArgsʹΑΔܕ҆શͳҾ਺ ɹɹˠɹ͜ΕΒ͕XMLͷϦιʔεͰఆٛͰ͖Δ ʢ͖ͬ͞ͷAS্ͷLayout EditorͰ௚ײతʹఆٛͰ͖Δʣ

  6. XMLͷϦιʔεͰఆٛͰ͖Δ <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" app:startDestination="@id/fragment_main" >

    <fragment android:id="@+id/fragment_main" android:name="com.yagi2.navigation.MainFragment" android:label="MainFragment" tools:layout="@layout/fragment_main" > </fragment> <fragment android:id="@+id/fragment_one" android:name="com.yagi2.navigation.FlowFragment" android:label="fragment_one" tools:layout="@layout/fragment_one" > </fragment> ……
  7. XMLͷϦιʔεͰఆٛͰ͖Δ <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" app:startDestination="@id/fragment_main" >

    <fragment android:id="@+id/fragment_main" android:name="com.yagi2.navigation.MainFragment" android:label="MainFragment" tools:layout="@layout/fragment_main" > </fragment> ……
  8. XMLͷϦιʔεͰఆٛͰ͖Δ <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" app:startDestination="@id/fragment_main" >

    <fragment android:id="@+id/fragment_main" android:name="com.yagi2.navigation.MainFragment" android:label="MainFragment" tools:layout="@layout/fragment_main" > </fragment> ……
  9. XMLͷϦιʔεͰఆٛͰ͖Δ <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" app:startDestination="@id/fragment_main" >

    <fragment android:id=“{֤ϑϥάϝϯτͷID}“ android:name="com.yagi2.navigation.MainFragment" android:label="MainFragment" tools:layout="@layout/fragment_main" > </fragment> ……
  10. XMLͷϦιʔεͰఆٛͰ͖Δ <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" app:startDestination="@id/fragment_main" >

    <fragment android:id=“{֤ϑϥάϝϯτͷID}“ android:name=“{ϑϥάϝϯτͷΫϥε}” android:label="MainFragment" tools:layout="@layout/fragment_main" > </fragment> ……
  11. XMLͷϦιʔεͰఆٛͰ͖Δ <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" app:startDestination="@id/fragment_main" >

    <fragment android:id=“{֤ϑϥάϝϯτͷID}“ android:name=“{ϑϥάϝϯτͷΫϥε}” android:label=“{Navigation EditorͰදࣔ͞ΕΔϥϕϧ}” tools:layout=“{Navigation EditorͰදࣔ͞ΕΔϨΠΞ΢τ}” > </fragment> ……
  12. XMLͷϦιʔεͰఆٛͰ͖Δ <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" app:startDestination="@id/fragment_main" >

    <fragment android:id="@+id/fragment_main" … <action android:id=“@+id/action_main_to_one” app:destination="@id/fragment_one" app:enterAnim="@anim/slide_in_right" app:exitAnim="@anim/slide_out_left" app:popEnterAnim="@anim/slide_in_left" app:popExitAnim="@anim/slide_out_right" /> </fragment> ……
  13. XMLͷϦιʔεͰఆٛͰ͖Δ <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" app:startDestination="@id/fragment_main" >

    <fragment android:id="@+id/fragment_main" … <action android:id=“@+id/action_main_to_one” app:destination="@id/fragment_one" app:enterAnim="@anim/slide_in_right" app:exitAnim="@anim/slide_out_left" app:popEnterAnim="@anim/slide_in_left" app:popExitAnim="@anim/slide_out_right" /> </fragment> ……
  14. XMLͷϦιʔεͰఆٛͰ͖Δ <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" app:startDestination="@id/fragment_main" >

    <fragment android:id="@+id/fragment_main" … <action android:id=“{ભҠΞΫγϣϯͷID}” app:destination="@id/fragment_one" app:enterAnim="@anim/slide_in_right" app:exitAnim="@anim/slide_out_left" app:popEnterAnim="@anim/slide_in_left" app:popExitAnim="@anim/slide_out_right" /> </fragment> ……
  15. XMLͷϦιʔεͰఆٛͰ͖Δ <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" app:startDestination="@id/fragment_main" >

    <fragment android:id="@+id/fragment_main" … <action android:id=“{ભҠΞΫγϣϯͷID}” app:destination=“{ભҠઌͷFragmentͷID}” app:enterAnim=“@anim/slide_in_right" app:exitAnim="@anim/slide_out_left" app:popEnterAnim="@anim/slide_in_left" app:popExitAnim="@anim/slide_out_right" /> </fragment> ……
  16. XMLͷϦιʔεͰఆٛͰ͖Δ <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" app:startDestination="@id/fragment_main" >

    <fragment android:id="@+id/fragment_main" … <action android:id=“{ભҠΞΫγϣϯͷID}” app:destination=“{ભҠઌͷFragmentͷID}” app:enterAnim=“{ΞχϝʔγϣϯϦιʔεͷID}“ app:exitAnim="{ΞχϝʔγϣϯϦιʔεͷID}" app:popEnterAnim="{ΞχϝʔγϣϯϦιʔεͷID}" app:popExitAnim=“{ΞχϝʔγϣϯϦιʔεͷID}" /> </fragment> ……
  17. XMLͷϦιʔεͰఆٛͰ͖Δ

  18. ͔͍͔ͭͨ ɾContainerʹͳΔActivityͷLayoutͰ<fragment> ɹΛఆٛ͢Δ ɾ”android:name”ʹ ”androidx.navigation.fragment.NavHostFragment” ɹΛηοτ͢Δ ɾ”app:navGraph”ʹఆٛͨ͠XMLΛηοτ͢Δ

  19. ͔͍͔ͭͨ <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"

    tools:context=".MainActivity" > <fragment android:id="@+id/fragment" android:layout_width="match_parent" android:layout_height="match_parent" android:name="androidx.navigation.fragment.NavHostFragment" app:navGraph="@navigation/nav_graph" app:defaultNavHost="true" /> </android.support.constraint.ConstraintLayout>
  20. ͔͍͔ͭͨ <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"

    tools:context=".MainActivity" > <fragment android:id="@+id/fragment" android:layout_width="match_parent" android:layout_height="match_parent" android:name="androidx.navigation.fragment.NavHostFragment" app:navGraph="@navigation/nav_graph" app:defaultNavHost="true" /> </android.support.constraint.ConstraintLayout>
  21. ͔͍͔ͭͨ <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"

    tools:context=".MainActivity" > <fragment android:id=“@+id/fragment" android:layout_width="match_parent" android:layout_height="match_parent" android:name="androidx.navigation.fragment.NavHostFragment" app:navGraph=“{͖ͬ͞ఆٛͨ͠XMLͷNavigation Graph}” app:defaultNavHost="true" /> </android.support.constraint.ConstraintLayout>
  22. ͔͍͔ͭͨ <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" app:startDestination="@id/fragment_main" >

    <fragment android:id="@+id/fragment_main" android:name="com.yagi2.navigation.MainFragment" android:label="MainFragment" tools:layout="@layout/fragment_main" > </fragment> <fragment android:id="@+id/fragment_one" android:name="com.yagi2.navigation.FlowFragment" android:label="fragment_one" tools:layout="@layout/fragment_one" > </fragment> ……
  23. ͔͍͔ͭͨ <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" app:startDestination="@id/fragment_main" >

    <fragment android:id="@+id/fragment_main" android:name="com.yagi2.navigation.MainFragment" android:label="MainFragment" tools:layout="@layout/fragment_main" > </fragment> <fragment android:id="@+id/fragment_one" android:name="com.yagi2.navigation.FlowFragment" android:label="fragment_one" tools:layout="@layout/fragment_one" > </fragment> ……
  24. ͔͍͔ͭͨ ɾભҠ͍ͤͨ͞λΠϛϯάͰ ɹɹɹNavigation.createNavigateOnClickListener(ભҠͷActionID) ɹΛݺͿ

  25. ͔͍͔ͭͨ class MainFragment : Fragment() { override fun onCreateView(………): View?

    { super.onCreateView(inflater, container, savedInstanceState) return inflater.inflate(R.layout.fragment_main, container , false) } override fun onViewCreated(………) { super.onViewCreated(view, savedInstanceState) view.findViewById<Button>(R.id.next_button).setOnClickListener( Navigation.createNavigateOnClickListener(R.id.action_main_to_one) ) } }
  26. ͔͍͔ͭͨ class MainFragment : Fragment() { override fun onCreateView(………): View?

    { super.onCreateView(inflater, container, savedInstanceState) return inflater.inflate(R.layout.fragment_main, container , false) } override fun onViewCreated(………) { super.onViewCreated(view, savedInstanceState) view.findViewById<Button>(R.id.next_button).setOnClickListener( Navigation.createNavigateOnClickListener(R.id.action_main_to_one) ) } }
  27. ͜Ε͚ͩ

  28. σϞʢ࿥ըʣ

  29. None
  30. SafeArgs

  31. MainFragmentͱ FlowFragmetͷ2ͭͰߏ੒

  32. SafeArgs <fragment android:id="@+id/fragment_one" android:name="com.yagi2.navigation.FlowFragment" android:label="fragment_one" … > <argument android:name="number" android:defaultValue="1"

    app:type="integer" /> <action android:id="@+id/action_next_flow" … /> </fragment>
  33. SafeArgs <fragment android:id="@+id/fragment_one" android:name="com.yagi2.navigation.FlowFragment" android:label="fragment_one" … > <argument android:name="number" android:defaultValue="1"

    app:type="integer" /> <action android:id="@+id/action_next_flow" … /> </fragment>
  34. SafeArgs class FlowFragment : Fragment() { override fun onCreateView(…): View?

    { super.onCreateView(…) val number = arguments?.getInt("number") return when (number) { 1 -> inflater.inflate(R.layout.fragment_one, container, false) 2 -> inflater.inflate(R.layout.fragment_two, container, false) 3 -> inflater.inflate(R.layout.fragment_three, container, false) else -> throw IllegalArgumentException() } } …
  35. SafeArgs class FlowFragment : Fragment() { override fun onCreateView(…): View?

    { super.onCreateView(…) val number = arguments?.getInt("number") return when (number) { 1 -> inflater.inflate(R.layout.fragment_one, container, false) 2 -> inflater.inflate(R.layout.fragment_two, container, false) 3 -> inflater.inflate(R.layout.fragment_three, container, false) else -> throw IllegalArgumentException() } } …
  36. SafeArgs class FlowFragment : Fragment() { override fun onCreateView(…): View?

    { super.onCreateView(…) val number = arguments?.getInt("number") return when (number) { 1 -> inflater.inflate(R.layout.fragment_one, container, false) 2 -> inflater.inflate(R.layout.fragment_two, container, false) 3 -> inflater.inflate(R.layout.fragment_three, container, false) else -> throw IllegalArgumentException() } } … Type Safe?
  37. Safe Args

  38. SafeArgs <fragment android:id="@+id/fragment_one" android:name="com.yagi2.navigation.FlowFragment" android:label="fragment_one" … > <argument android:name="number" android:defaultValue="1"

    app:type="integer" /> <action android:id="@+id/action_next_flow" … /> </fragment>
  39. SafeArgs public class FlowFragmentArgs { private int number = 3;

    private FlowFragmentArgs() { } public static FlowFragmentArgs fromBundle(Bundle bundle) { FlowFragmentArgs result = new FlowFragmentArgs(); if (bundle.containsKey("number")) { result.number = bundle.getInt("number"); } return result; } public int getNumber() { return number; } public Bundle toBundle() { Bundle __outBundle = new Bundle(); __outBundle.putInt("number", this.number); return __outBundle; }
  40. SafeArgs public class FlowFragmentArgs { private int number = 3;

    private FlowFragmentArgs() { } public static FlowFragmentArgs fromBundle(Bundle bundle) { FlowFragmentArgs result = new FlowFragmentArgs(); if (bundle.containsKey("number")) { result.number = bundle.getInt("number"); } return result; } public int getNumber() { return number; } public Bundle toBundle() { Bundle __outBundle = new Bundle(); __outBundle.putInt("number", this.number); return __outBundle; } Type Safe! ☺
  41. SafeArgs class FlowFragment : Fragment() { override fun onCreateView(…): View?

    { super.onCreateView(…) val number = arguments?.let { FlowFragmentArgs.fromBundle(it).number } return when (number) { 1 -> inflater.inflate(R.layout.fragment_one, container, false) 2 -> inflater.inflate(R.layout.fragment_two, container, false) 3 -> inflater.inflate(R.layout.fragment_three, container, false) else -> throw IllegalArgumentException() } } …
  42. SafeArgs class FlowFragment : Fragment() { override fun onCreateView(…): View?

    { super.onCreateView(…) val number = arguments?.let { FlowFragmentArgs.fromBundle(it).number } return when (number) { 1 -> inflater.inflate(R.layout.fragment_one, container, false) 2 -> inflater.inflate(R.layout.fragment_two, container, false) 3 -> inflater.inflate(R.layout.fragment_three, container, false) else -> throw IllegalArgumentException() } } …
  43. ·ͱΊ ɾNavigation͸͔ͬ͠Γ࢖͍͚ͬͯ͹ศརͦ͏ ɾSafeArgs͸࢖Θͳ͍ཧ༝͕ແ͍͘Β͍ʹྑͦ͞͏ ɾʢݸਓతʹ͸ʣFragmentTransaction΄͕͛ແ͍ͷͰָ ࠓճͷιʔε yagi2/Android-Navigation-Sample ɹhttps://github.com/yagi2/Android-Navigation-Sample

  44. ৄղͷ঺հ ɾʲAndroidʳGoogle IO 2018Ͱ৽ൃද͞Εͨ navigation ʹ ͍ͭͯͷৄࡉϨϙʔτ - DMM inside

    ɹ https://inside.dmm.com/entry/2018/05/25/android- navigation ɾNavigation Component // Speaker Deck ɹhttps://speakerdeck.com/satsukies/navigation-component