Flutter Debugging
Finding and fixing bugs in your Flutter apps
🐛 What is Debugging?
Debugging helps you find and fix errors in your code. Flutter provides powerful tools like print statements, debugger, and DevTools to inspect your app's behavior and solve problems quickly.
// Simple debugging with print
void calculateTotal(int price) {
print('Price: $price'); // Check value
int total = price * 2;
print('Total: $total'); // Verify result
}
Console Output:
Price: 50
Total: 100
Debugging Tools
Print Statements
Simple console logging
print('Debug: $value');
Debugger
Pause and inspect code
// Set breakpoint
debugger();
DevTools
Visual debugging interface
flutter pub global
activate devtools
Error Messages
Read stack traces
Exception: Error
at line 42
🔹 Using Print Statements
The simplest way to debug:
import 'package:flutter/material.dart';
class DebugExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('🔵 Building DebugExample widget');
String username = 'John';
print('👤 Username: $username');
int age = 25;
print('📅 Age: $age');
List items = ['Apple', 'Banana', 'Orange'];
print('🛒 Items: $items');
print('📊 Item count: ${items.length}');
return Scaffold(
appBar: AppBar(title: Text('Debug Demo')),
body: Center(
child: ElevatedButton(
onPressed: () {
print('🔘 Button pressed!');
print('⏰ Time: ${DateTime.now()}');
},
child: Text('Click Me'),
),
),
);
}
}
Console Output:
🔵 Building DebugExample widget
👤 Username: John
📅 Age: 25
🛒 Items: [Apple, Banana, Orange]
📊 Item count: 3
🔹 Using Breakpoints
Pause execution to inspect variables:
class Calculator {
int add(int a, int b) {
// Click left of line number to set breakpoint
int result = a + b; // ← Set breakpoint here
return result;
}
void calculate() {
int x = 10;
int y = 20;
// When breakpoint hits, you can:
// - Check x and y values
// - Step through code line by line
// - Watch variable changes
int sum = add(x, y);
print('Sum: $sum');
}
}
// Steps to use breakpoints:
// 1. Click left margin to add red dot
// 2. Run in Debug mode (F5)
// 3. App pauses at breakpoint
// 4. Inspect variables in Debug panel
// 5. Use Step Over (F10) to continue
🔹 Debug Console Commands
Useful commands while debugging:
Common Commands:
- p variable - Print variable value
- p this - Print current object
- p widget.runtimeType - Check widget type
- Continue (F5) - Resume execution
- Step Over (F10) - Next line
- Step Into (F11) - Enter function
- Step Out (Shift+F11) - Exit function
🔹 Flutter DevTools
Powerful visual debugging tools:
# Install DevTools
flutter pub global activate devtools
# Run DevTools
flutter pub global run devtools
# Or open from VS Code
# Click "Dart DevTools" in debug toolbar
DevTools Features:
- Widget Inspector: Visual widget tree
- Timeline: Performance analysis
- Memory: Track memory usage
- Network: Monitor API calls
- Logging: View all logs
- Debugger: Advanced debugging
🔹 Common Errors & Solutions
How to fix typical Flutter errors:
🔸 Null Safety Error
// ❌ Error: Null check operator used on null value
String? name;
print(name!.length); // Crashes!
// ✅ Solution: Check for null first
String? name;
if (name != null) {
print(name.length);
}
// ✅ Or use null-aware operator
print(name?.length ?? 0);
🔸 Widget Overflow Error
// ❌ Error: RenderFlex overflowed
Row(
children: [
Text('Very long text that exceeds screen width...'),
],
)
// ✅ Solution: Use Expanded or Flexible
Row(
children: [
Expanded(
child: Text('Very long text that exceeds screen width...'),
),
],
)
🔸 setState Error
// ❌ Error: setState called after dispose
class MyWidget extends StatefulWidget {
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State {
@override
void dispose() {
super.dispose();
}
void updateData() {
// ✅ Check if mounted before setState
if (mounted) {
setState(() {
// Update state
});
}
}
}
🔹 Debug Mode vs Release Mode
Understanding different build modes:
Debug Mode (Default):
- Hot Reload enabled
- Debugging tools available
- Slower performance
- Larger app size
- Command: flutter run
Release Mode:
- No debugging tools
- Optimized performance
- Smaller app size
- For production
- Command: flutter run --release
🔹 Logging Best Practices
Better than print() for production:
import 'dart:developer' as developer;
class LoggingExample {
void demonstrateLogs() {
// Simple print (removed in release)
print('Simple message');
// Developer log (better for debugging)
developer.log('User logged in', name: 'Auth');
// Log with details
developer.log(
'API call failed',
name: 'Network',
error: 'Connection timeout',
level: 1000, // Error level
);
// Log with object
Map userData = {
'id': 123,
'name': 'John',
};
developer.log(
'User data',
name: 'UserService',
error: userData,
);
}
}
🔹 Assert Statements
Catch bugs during development:
class ValidationExample {
void processAge(int age) {
// Assert only runs in debug mode
assert(age >= 0, 'Age cannot be negative');
assert(age <= 150, 'Age seems invalid');
print('Processing age: $age');
}
void processName(String? name) {
assert(name != null, 'Name is required');
assert(name!.isNotEmpty, 'Name cannot be empty');
print('Hello, $name');
}
}
void main() {
var validator = ValidationExample();
validator.processAge(25); // ✅ Works
// validator.processAge(-5); // ❌ Assertion fails in debug
validator.processName('John'); // ✅ Works
// validator.processName(''); // ❌ Assertion fails in debug
}
🔹 Debugging Tips
Pro tips for effective debugging:
Quick Tips:
- Use descriptive print messages with emojis
- Add timestamps to track execution order
- Use try-catch blocks for error handling
-
Check Flutter Doctor:
flutter doctor -
Clear build cache:
flutter clean - Restart IDE if debugging stops working
- Read error messages carefully - they help!
- Use Widget Inspector to visualize layout