The MVVM pattern helps organize your Flutter app by separating the user interface from the business logic. This makes your app easier to build, test, and maintain.
MVVM pattern in Flutter
class ViewModel { // Holds data and logic } class View extends StatelessWidget { final ViewModel viewModel; View(this.viewModel); @override Widget build(BuildContext context) { // Use viewModel to build UI return Container(); } }
The ViewModel holds the app data and logic.
The View listens to the ViewModel and updates the UI.
class CounterViewModel { int count = 0; void increment() { count++; } }
class CounterView extends StatelessWidget { final CounterViewModel viewModel; CounterView(this.viewModel); @override Widget build(BuildContext context) { return Text('Count: ${viewModel.count}'); } }
This app uses MVVM to separate the counter logic from the UI. The ViewModel holds the count and notifies the View when it changes. The View listens and updates the displayed count.
import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter/material.dart'; class CounterViewModel extends ChangeNotifier { int _count = 0; int get count => _count; void increment() { _count++; notifyListeners(); } } class CounterView extends StatelessWidget { final CounterViewModel viewModel; CounterView({required this.viewModel}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('MVVM Counter')), body: Center( child: AnimatedBuilder( animation: viewModel, builder: (context, _) { return Text('Count: ${viewModel.count}', style: TextStyle(fontSize: 30)); }, ), ), floatingActionButton: FloatingActionButton( onPressed: viewModel.increment, child: Icon(Icons.add), tooltip: 'Increment', ), ); } } void main() { final viewModel = CounterViewModel(); runApp(MaterialApp(home: CounterView(viewModel: viewModel))); }
Use ChangeNotifier in ViewModel to notify the View about data changes.
Use AnimatedBuilder or ValueListenableBuilder in the View to rebuild UI on changes.
Keep UI code simple and put all logic in the ViewModel.
MVVM separates UI (View) from logic (ViewModel) for cleaner code.
ViewModel holds data and notifies View when data changes.
View listens to ViewModel and updates UI automatically.
Practice
Solution
Step 1: Understand MVVM roles
The ViewModel acts as a middleman holding data and logic separate from UI.Step 2: Identify ViewModel responsibility
It notifies the View when data changes so UI updates automatically.Final Answer:
To hold data and business logic, notifying the View of changes -> Option BQuick Check:
ViewModel = Data + Logic holder [OK]
- Confusing ViewModel with View
- Thinking ViewModel handles UI rendering
- Assuming ViewModel manages navigation
Solution
Step 1: Recall ChangeNotifier usage
ChangeNotifier requires calling notifyListeners() to update listeners.Step 2: Identify correct notification method
notifyListeners() triggers UI rebuilds in listening Views.Final Answer:
call notifyListeners() inside the ViewModel after data update -> Option AQuick Check:
notifyListeners() updates View [OK]
- Using setState() inside ViewModel (wrong place)
- Trying to call build() manually
- Calling dispose() instead of notifyListeners()
class CounterViewModel extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
What will be the value of count after calling increment() twice starting from 0?Solution
Step 1: Analyze initial value and increment
_count starts at 0, increment() adds 1 each call.Step 2: Calculate after two increments
After two calls, _count = 0 + 1 + 1 = 2.Final Answer:
2 -> Option CQuick Check:
Two increments = count 2 [OK]
- Forgetting notifyListeners() updates UI but doesn't change count
- Assuming count resets after notifyListeners()
- Confusing initial value with updated value
class UserViewModel extends ChangeNotifier {
String _name = '';
String get name => _name;
void updateName(String newName) {
_name = newName;
}
}
Why won't the UI update when updateName is called?Solution
Step 1: Check data update method
updateName changes _name but does not notify listeners.Step 2: Understand UI update trigger
Without notifyListeners(), UI won't rebuild on data change.Final Answer:
notifyListeners() is missing after updating _name -> Option AQuick Check:
Missing notifyListeners() blocks UI update [OK]
- Forgetting notifyListeners() after state change
- Thinking getter name causes UI update
- Assuming async needed without async code
Solution
Step 1: Understand MVVM data flow
ViewModel holds data and notifies View on changes using ChangeNotifier.Step 2: Identify correct Flutter pattern
Calling notifyListeners() after list changes triggers Consumer widget rebuild in View.Step 3: Eliminate incorrect options
setState() belongs in View, not ViewModel; manual build() calls are incorrect; storing list only in View breaks MVVM.Final Answer:
Use a ChangeNotifier in ViewModel, call notifyListeners() after modifying the list, and use a Consumer widget in View -> Option DQuick Check:
ChangeNotifier + notifyListeners() + Consumer = MVVM update [OK]
- Calling setState() in ViewModel instead of View
- Modifying data only in View without notifications
- Manually calling build() method
Ready to prove it?
Pass the test and this pattern moves unknown
