Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Single Activity with MVVM

Single Activity with MVVM

TakuSemba

March 26, 2019
Tweet

More Decks by TakuSemba

Other Decks in Technology

Transcript

  1. TakuSemba CyberAgent.Inc Single Activity with MVVM

  2. TakuSemba CyberAgent.Inc Single Activity with MVVM

  3. @takusemba https://github.com/TakuSemba

  4. https://developer.android.com/jetpack/docs/guide MVVM

  5. Navigation https://developer.android.com/guide/navigation/navigation-getting-started

  6. <?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" android:id="@+id/nav_graph"> </navigation>

  7. <?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" android:id="@+id/nav_graph"> <fragment android:id="@+id/firstFragment"

    android:name=“your.package.FirstFragment” /> <fragment android:id="@+id/secondFragment" android:name=“your.package.SecondFragment”/> </navigation> <navigation <fragment android:id="@+id/firstFragment" android:name=“your.package.FirstFragment" /> <fragment android:id="@+id/secondFragment" android:name="your.package.SecondFragment"/> </navigation>
  8. <?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" android:id="@+id/nav_graph" app:startDestination="@id/firstFragment"> <fragment

    android:id="@+id/firstFragment" android:name=“your.package.FirstFragment” /> <fragment android:id="@+id/secondFragment" android:name=“your.package.SecondFragment”/> </navigation> <navigation app:startDestination="@id/firstFragment"> <fragment android:id="@+id/firstFragment" android:name=“your.package.FirstFragment" /> <fragment android:id="@+id/secondFragment" android:name="your.package.SecondFragment"/> </navigation>
  9. <?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" android:id="@+id/nav_graph" app:startDestination="@id/firstFragment"> <fragment

    android:id="@+id/firstFragment" android:name=“your.package.FirstFragment"> <action android:id="@+id/to_secondFragment" app:destination="@id/secondFragment"/> </fragment> <fragment android:id="@+id/secondFragment" android:name=“your.package.SecondFragment"/> </navigation> <fragment android:id="@+id/firstFragment" android:name="your.package.FirstFragment"> <action android:id="@+id/to_secondFragment" app:destination="@id/secondFragment"/> </fragment>
  10. <?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" android:id="@+id/nav_graph" app:startDestination="@id/firstFragment"> <fragment

    android:id="@+id/firstFragment" android:name="your.package.FirstFragment"> <action android:id="@+id/to_secondFragment" app:destination="@id/secondFragment"/> </fragment> <fragment android:id="@+id/secondFragment" android:name=“your.package.SecondFragment"> <argument android:name="userId" app:argType="string"/> </fragment> </navigation> <fragment android:id="@+id/secondFragment" android:name=“your.package.SecondFragment"> <argument android:name="userId" app:argType="string"/> </fragment>
  11. <?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" android:id="@+id/nav_graph" app:startDestination="@id/firstFragment"> <fragment

    android:id="@+id/firstFragment" android:name="your.package.FirstFragment"> <action android:id="@+id/to_secondFragment" app:destination="@id/secondFragment"/> </fragment> <fragment android:id="@+id/secondFragment" android:name=“your.package.SecondFragment"> <argument android:name="userId" app:argType="string"/> </fragment> </navigation>
  12. None
  13. val navController = findNavController(R.id.host_fragment) // find from activity

  14. val navController = findNavController(R.id.host_fragment) // find from activity val navController

    = findNavController() // find from fragment
  15. val navController = findNavController(R.id.host_fragment) // find from activity val navController

    = findNavController() // find from fragment val navController = findNavController() // find from view
  16. val navController = findNavController(R.id.host_fragment) // find from activity val navController

    = findNavController() // find from fragment val navController = findNavController() // find from view val args = bundleOf(SecondFragment.KEY_USER_ID to userId) navController.navigate(R.id.toSecondFragment, args) // navigate to secondFragment.kt
  17. val navController = findNavController(R.id.host_fragment) // find from activity val navController

    = findNavController() // find from fragment val navController = findNavController() // find from view // navigate to secondFragment.kt val directions = FirstFragmentDirections.toSecondFragment(userId) navController.navigate(directions)
  18. val navController = findNavController(R.id.host_fragment) // find from activity val navController

    = findNavController() // find from fragment val navController = findNavController() // find from view // navigate to secondFragment.kt val directions = FirstFragmentDirections.toSecondFragment(userId) navController.navigate(directions) // get userId from arguments val args = SecondFragmentArgs.fromBundle(requireArguments()) val userId = args.userId
  19. val navController = findNavController(R.id.host_fragment) // find from activity val navController

    = findNavController() // find from fragment val navController = findNavController() // find from view // navigate to secondFragment.kt val directions = FirstFragmentDirections.toSecondFragment(userId) navController.navigate(directions) // get userId from arguments private val args by navArgs<SecondFragmentArgs>() val userId = args.userId
  20. Global Action a common action that multiple destinations can use

  21. Global Action a common action that multiple destinations can use

    ɾMaintenance ɾForceUpdate ɾError
  22. // global action

  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" android:id="@+id/nav_graph" app:startDestination="@id/launcherFragment" > <action

    android:id="@+id/action_global_ maintainanceFragment” app:destination="@id/maintainanceFragment" /> <fragment … /> <fragment … /> </navigation> // global action
  24. // navigate to maintainanceFragment using GlobalAction val directions = NavGraphDirections.actionGlobalMaintainanceFragment()

  25. // navigate to maintainanceFragment using GlobalAction val directions = NavGraphDirections.actionGlobalMaintainanceFragment()

    navController.navigate(directions)
  26. Nav Options special options for navigate actions public NavOptions.Builder setPopUpTo

    (int destinationId, boolean inclusive) public NavOptions.Builder setLaunchSingleTop (boolean singleTop) …
  27. // navigate with stacked fragmetns popoed up

  28. val directions = SplashDirections.showLoginFragment() navController.navigate(directions) // navigate with stacked fragmetns

    popoed up
  29. val directions = SplashDirections.showLoginFragment() val options = NavOptions.Builder() .setPopUpTo(R.id.splashFragment, true)

    .build() navController.navigate(directions, options) // navigate with stacked fragmetns popoed up
  30. // navigate to loginFragment val directions = SplashDirections.showLoginFragment() navController.navigate(directions) <?xml

    version="1.0" encoding="utf-8"?> <navigation> <fragment android:id="@+id/splashFragment" android:name="your.package.SplashFragment" tools:layout="@layout/fragment_splash"> <action android:id="@+id/showLoginFragment" app:destination="@id/loginFragment" app:popUpTo="@id/splashFragment" app:popUpToInclusive="true"/> </fragment> </navigation> <action app:popUpTo="@id/splashFragment" app:popUpToInclusive="true"/> // navigate with stacked fragmetns popoed up
  31. // navigate as single-top val directions = NavGraphDirections.showBarFragment() navController.navigate(directions) val

    directionsAgain = NavGraphDirections.showBarFragment() navController.navigate(directionsAgain)
  32. val directions = NavGraphDirections.showBarFragment() navController.navigate(directions) val directionsAgain = NavGraphDirections.showBarFragment() val

    options = NavOptions.Builder() .setLaunchSingleTop(true) .build() navController.navigate(directions, options) // navigate as single-top
  33. // navigate to barFragment val directions = NavGraphDirections.showBarFragment() navController.navigate(directions) <?xml

    version="1.0" encoding="utf-8"?> <navigation> <fragment android:id="@+id/splashFragment" android:name="your.package.SplashFragment" tools:layout="@layout/fragment_splash"> <action android:id="@+id/showLoginFragment" app:destination="@id/loginFragment" app:launchSingleTop="true"/> </fragment> </navigation> <action app:launchSingleTop="true"/> // navigate as single-top
  34. // navigate back

  35. navController.popBackStack() // navigate back

  36. navController.popBackStack() // navigate back // observe data override fun onViewCreated(view:

    View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewModel.user.observe(this) { user -> textView.text = user.name } }
  37. navController.popBackStack() // navigate back // observe data override fun onViewCreated(view:

    View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewModel.user.observe(this) { user -> textView.text = user.name } } observe(this) { user -> }
  38. navController.popBackStack() // navigate back // observe data override fun onViewCreated(view:

    View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewModel.user.observe(this) { user -> textView.text = user.name } } observe(this) { user -> } override fun onDestroy() { super.onDestroy() // not called yet }
  39. navController.popBackStack() // navigate back // observe data override fun onViewCreated(view:

    View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewModel.user.observe(viewLifecycleOwner) { user -> textView.text = user.name } } override fun onDestroy() { super.onDestroy() // not called yet } observe(viewLifecycleOwner) { user -> }
  40. navController.popBackStack() // navigate back // observe data override fun onViewCreated(view:

    View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewModel.user.observe(viewLifecycleOwner) { user -> textView.text = user.name } } override fun onDestroyView() { super.onDestroyView() // observer is removed. } observe(viewLifecycleOwner) { user -> }
  41. IUUQTNFEJVNDPN!UBLVTFNCB

  42. class FooViewModel : ViewModel() { val snackbarMessage: LiveData<SnackbarMessage> = MutableLiveData()

    } // viewModel
  43. class FooViewModel : ViewModel() { val snackbarMessage: LiveData<SnackbarMessage> = MutableLiveData()

    } // viewModel // observe data override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewModel.snackbarMessage.observe(viewLifecycleOwner) { message -> // show snackbar } }
  44. class FooViewModel : ViewModel() { val snackbarMessage: LiveData<Event<SnackbarMessage>> = MutableLiveData()

    } // viewModel // observe data override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewModel.snackbarMessage.observe(viewLifecycleOwner) { message -> // show snackbar } }
  45. class FooViewModel : ViewModel() { val snackbarMessage: LiveData<Event<SnackbarMessage>> = MutableLiveData()

    } // viewModel // observe data override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewModel.snackbarMessage.observe(viewLifecycleOwner) { message -> // show snackbar } } // Event.kt from https://github.com/google/iosched LiveData<Event<SnackbarMessage>>
  46. class FooViewModel : ViewModel() { // Event.kt from https://github.com/google/iosched val

    snackbarMessage: LiveData<Event<SnackbarMessage>> = MutableLiveData() } // viewModel // observe data override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewModel.snackbarMessage.observe(viewLifecycleOwner) { event -> event.getContentIfNotHandled()?.let { message -> // show snackbar } } }
  47. IUUQTNFEJVNDPNBOESPJEEFWFMPQFSTMJWFEBUBXJUITOBDLCBSOBWJHBUJPOBOEPUIFSFWFOUTUIF TJOHMFMJWFFWFOUDBTFBD

  48. // scope for viewModel val activityScopedViewModel = ViewModelProviders .of(requireActivity(), viewModelFactory)

    .get(FooViewModel::class.java)
  49. // scope for viewModel private val activityScopedViewModel: FooViewModel by activityViewModels

    { viewModelFactory }
  50. // scope for viewModel private val activityScopedViewModel: FooViewModel by activityViewModels

    { viewModelFactory } Activity Scope
  51. // scope for viewModel private val activityScopedViewModel: FooViewModel by activityViewModels

    { viewModelFactory } Activity Scope ≒ App Scope
  52. // scope for viewModel private val activityScopedViewModel: FooViewModel by activityViewModels

    { viewModelFactory } private val fragmentScopedViewModel: BarViewModel by viewModels { viewModelFactory } Activity Scope ≒ App Scope
  53. // scope for viewModel private val activityScopedViewModel: FooViewModel by activityViewModels

    { viewModelFactory } private val fragmentScopedViewModel: BarViewModel by viewModels { viewModelFactory } Activity Scope ≒ App Scope … Fragment Scope Fragment Scope
  54. https://www.youtube.com/watch?v=2k8x8V77CrU&t=1300s

  55. https://github.com/takusemba https://twitter.com/takusemba Single Activity with MVVM