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

🧠 Test Your Knowledge

What is the simplest way to debug in Flutter?