androidviewmodelandroid-architecture-navigationapplication-lifecycle

Android Navigation Component - Store/Access Data throughout App Lifecycle


In Android, we can use Singleton pattern to store data that we require across multiple activities during the whole app lifecycle. This is considered a memory leak and has its cons, but practically speaking, this approach is used widely (at least in Android programming).

Coming to the main point, in Navigation Component, we follow a single activity pattern which remains available throughout the app lifecycle. Also, this documentation says that a shared activity-level ViewModel can be used to share data between different fragments. I think this is a fairly reasonable way to share data between multiple fragments but I still want to validate this approach before going ahead and using it with Navigation Component. My question is whether we should use an activity-level ViewModel to store small amounts of data that I need throughout the app lifecycle in a Navigation Component based application (remember I only have a single activity)? Also, what implications/pros/cons this approach can have over the Singleton-based approach?


Solution

  • If you're planning to move to a single activity architecture for your app, you can surely share data by using the same view model across fragments. To do so you can use a Kotlin property delegate from the fragment-ktx artifact.

    Let's say you like to share the same data between a master and a detail fragment, the only thing you'll need to do is to declare two view model instances in the two fragment that have the same activity scope:

    class MasterFragment : Fragment() {
    
        // Use the 'by activityViewModels()' Kotlin property delegate
        // from the fragment-ktx artifact
        private val model: SharedViewModel by activityViewModels()
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            model.state.observe(viewLifecycleOwner, {
              // do something with your state
            })
        }
    }
    
    class DetailFragment : Fragment() {
    
        // same scope of your MasterFragment
        private val model: SharedViewModel by activityViewModels()
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            model.state.observe(viewLifecycleOwner, {
              // do something with your state
            })
        }
    }
    

    Pros:

    In addition, the use of a singleton pattern is suggested for "application level" entities, such a database or a hardware resource, I would definitely not recommend to use a singleton for something so related to the UI like a view model class.