Pro Yearly is on sale from $80 to $50! »

Single Activity with MVVM

Single Activity with MVVM

A374f41eab3f73c50d8bab0652cb207a?s=128

TakuSemba

March 26, 2019
Tweet

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