1

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?

Abdul Mateen
  • 1,418
  • 1
  • 14
  • 32
  • 2
    "but practically speaking, this approach is used widely (at least in Android programming)." -> not really, perhaps via some Dependency INjection (Hilt, Dagger, Koin) where we have our "component factories" returning (and guaranteeing) an single instance of an object, but in practice, this is only used (or should) for certain things like databases and resources that make no sense in being instantiated multiple times. – Martin Marconcini Feb 15 '21 at 09:46
  • I totally understand and agree. But even then, Singletons aren't as strongly opposed in Android dev circles as in some other dev circles. – Abdul Mateen Feb 15 '21 at 09:49
  • 1
    True, perhaps because of people coming from other languages and tools (and well.. Java in general), but you should always try to avoid them (not just because of "memory leaks" but because more often than not, they are a source of problems anywhere you look. Anyway, just wanted to clarify that. :) – Martin Marconcini Feb 15 '21 at 10:03
  • Regarding the question in general. If you have a small amount of data, a single ViewModel will suffice; keep in mind that ViewModels are not data storage places, they are nor (or should not) be repositories, or "single source of truth" places. They are merely intermediate artifacts that survive a little bit longer than an Activity/Fragment/View, in a lifecycle-aware way (meaning they clean up for themselves and all that stuff), but they are not magical "singleton-like" components. – Martin Marconcini Feb 15 '21 at 10:12

1 Answers1

2

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:

  • lifecycle awareness: Differently than a singleton based approach you don't risk unexpected memory leaks because view model instances follow the parent activity lifecycle, so you don't need to programmatically set their instances to null when your fragments get destroyed. In a nutshell, you'll not risk to keep references to invalid contexts
  • no tight coupling: with a singleton approach, probably you'll make your fragments dependent from an instance of view model defined in your activity. That is bad for testability and violates Single Responsibility Principle

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.

Nicola Gallazzi
  • 7,897
  • 6
  • 45
  • 64