The Massive ViewModel Anti-Pattern
The most common MVVM failure is the 'Massive ViewModel', where business logic, input validation, data formatting, and even navigation decisions all pile up inside a single ViewModel class — effectively recreating the 'Massive View Controller' problem MVVM was adopted to solve, just one layer removed. The fix is extracting logic into dedicated use cases, validators, or formatter classes, leaving the ViewModel as a thin coordinator that wires those pieces to observable state.
Cricket analogy: It's like an all-rounder trying to open the batting, bowl the powerplay overs, and captain the side all at once — eventually one role suffers, so a good team distributes those responsibilities.
Leaking View References
Storing a direct reference to an Activity, Fragment, Context, or UIViewController inside a ViewModel field is a frequent source of memory leaks, because the ViewModel typically outlives a single View instance across configuration changes, and the retained reference prevents the View from being garbage collected. The fix is communicating through events, such as a SharedFlow or Channel of one-off UI events, or an Application-scoped context when platform access is unavoidable, never storing a View callback directly on the ViewModel.
Cricket analogy: It's like a bowler refusing to hand the ball back to the umpire between overs, holding onto it long after their spell has ended and disrupting the next bowler's setup.
// BAD: leaks the Activity and breaks platform independence
class ProfileViewModel(private val activity: MainActivity) : ViewModel() {
fun onSaveClicked() {
activity.showToast("Saved!")
}
}
// BETTER: emit a one-off event, let the View decide how to render it
class ProfileViewModel(private val repository: ProfileRepository) : ViewModel() {
private val _events = MutableSharedFlow<ProfileEvent>()
val events: SharedFlow<ProfileEvent> = _events
fun onSaveClicked() = viewModelScope.launch {
repository.save()
_events.emit(ProfileEvent.Saved)
}
}Overusing Two-Way Binding
Binding every field bidirectionally without any validation or gating logic can produce cascading, hard-to-trace updates — for example, a WPF property setter that raises INotifyPropertyChanged, which triggers a converter, which updates another bound property, which raises another change notification. The fix is being selective about which fields actually need two-way binding and preferring explicit command-driven mutation for anything that affects multiple pieces of state at once.
Cricket analogy: It's like a scoreboard operator manually recalculating the run rate, required run rate, and win probability separately every single ball instead of deriving them all from one authoritative score update.
Keep navigation decisions out of View code by exposing a navigation event (a sealed class or an event stream) from the ViewModel that the View observes and acts on. This keeps the ViewModel platform-agnostic while still letting it decide when navigation should happen.
Ignoring Lifecycle and State Restoration
Assuming a ViewModel simply survives forever ignores two real lifecycle events: configuration changes (screen rotation) and process death, where the operating system reclaims memory and later recreates the ViewModel from scratch. Without saving critical in-progress state to something like Android's SavedStateHandle, or an equivalent persistence mechanism on other platforms, users lose form input, scroll position, or multi-step wizard progress the moment the OS reclaims memory in the background.
Cricket analogy: It's like a rain delay wiping a batter's mental count of balls faced if nobody bothered to record it on the official scorecard — the moment play resumes, that context is gone.
These pitfalls rarely show up in day-to-day manual testing because a freshly launched app on a fast device hides memory leaks and state-loss bugs. They tend to surface only in production, on low-memory devices or after extended background time, so proactive testing and profiling matter more than they might seem to during development.
- The Massive ViewModel anti-pattern recreates the Massive View Controller problem MVVM was meant to fix — extract logic into use cases and formatters.
- Never store a direct reference to an Activity/Fragment/Context/UIViewController inside a ViewModel field; it causes memory leaks.
- Communicate one-off UI actions through events (SharedFlow, Channel) rather than direct method calls into the View.
- Unrestricted two-way binding on every field can trigger cascading, hard-to-trace change notifications.
- Keep navigation decisions in the ViewModel as observable events, not as direct View manipulation.
- Persist critical in-progress state (e.g., via SavedStateHandle) to survive configuration changes and process death.
- Many MVVM pitfalls are invisible in quick manual testing and only surface under production conditions like low memory.
Practice what you learned
1. What problem does the 'Massive ViewModel' anti-pattern most closely mirror?
2. Why does storing an Activity or Context reference inside a ViewModel cause a memory leak?
3. What is the recommended way for a ViewModel to trigger navigation?
4. Why can unrestricted two-way binding across many fields become a problem?
Was this page helpful?
You May Also Like
Testing ViewModels
How to unit test MVVM ViewModels in isolation, covering state assertions, command execution, async flows, and dependency mocking.
MVVM Best Practices
Practical guidelines for structuring ViewModels, bindings, and data flow so MVVM code stays maintainable at scale.
MVVM Interview Questions
Frequently asked MVVM interview questions with model answers, covering architecture fundamentals, data binding, and comparisons to MVC/MVP.
Related Reading
Related Study Notes in Microsoft Technologies
Browse all study notesWindows 10 / UWP Development Study Notes
.NET · 30 topics
Microsoft TechnologiesWindows Batch Scripting Study Notes
Batch · 30 topics
Microsoft TechnologiesMFC (Microsoft Foundation Classes) Study Notes
C++ · 30 topics
Microsoft TechnologiesSilverlight Study Notes
.NET · 30 topics
Microsoft TechnologiesXAML Study Notes
.NET · 30 topics
Microsoft TechnologiesWPF (Windows Presentation Foundation) Study Notes
.NET · 30 topics