Question #208MediumFlutter Basics

How to analyse the bug in flutter in all angle ?

#flutter

Answer

How to Analyze Bugs in Flutter from All Angles

Effective bug analysis requires a systematic approach, examining issues from multiple perspectives - code, performance, UI, and user experience.

1. Reproduction Analysis

First Step: Reproduce the Bug

dart
// Document reproduction steps
/*
BUG REPORT:
Steps to Reproduce:
1. Open app
2. Navigate to ProfileScreen
3. Tap "Edit Profile" button
4. App crashes

Expected: Profile edit screen opens
Actual: App crashes with null pointer exception
Device: Pixel 6, Android 13
Flutter Version: 3.16.0
*/

Create Test Case:

dart
testWidgets('Edit profile button should open edit screen', (tester) async {
  await tester.pumpWidget(MyApp());

  // Navigate to profile
  await tester.tap(find.byIcon(Icons.person));
  await tester.pumpAndSettle();

  // Tap edit button
  await tester.tap(find.text('Edit Profile'));
  await tester.pumpAndSettle();

  // Verify edit screen opens
  expect(find.byType(ProfileEditScreen), findsOneWidget);
});

2. Stack Trace Analysis

Read the Error Stack:

dart
// Example error
/*
======== Exception caught by widgets library =======
The following _TypeError was thrown building ProfileScreen:
Null check operator used on a null value

The relevant error-causing widget was:
  ProfileScreen ProfileScreen:file:///app/lib/screens/profile_screen.dart:15:7

When the exception was thrown, this was the stack:
#0      _ProfileScreenState.build (package:myapp/screens/profile_screen.dart:45:28)
#1      StatefulElement.build (package:flutter/src/widgets/framework.dart:4919:27)
...
*/

Analyze the Stack:

dart
// Line 45 in profile_screen.dart
Widget build(BuildContext context) {
  final user = widget.user!; // ❌ Null check operator on potentially null value

  // ✅ Fix: Add null safety check
  final user = widget.user;
  if (user == null) {
    return Center(child: Text('No user data'));
  }

  return Text(user.name);
}

3. Debug Tools Analysis

Use Flutter DevTools:

bash
# Launch DevTools
flutter pub global activate devtools
flutter pub global run devtools

Inspector Analysis:

dart
// Add debugging info
class DebugWidget extends StatelessWidget {
  
  Widget build(BuildContext context) {
    // Use debugPrint for controlled logging
    debugPrint('Building DebugWidget');
    debugPrint('Context: $context');

    return Container(
      // Add debug label
      key: ValueKey('debug-container'),
      child: Text('Debug'),
    );
  }
}

4. Performance Analysis

CPU Profiling:

dart
import 'dart:developer' as developer;

class PerformanceTest extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () {
        // Profile expensive operation
        developer.Timeline.startSync('ExpensiveOperation');

        try {
          performExpensiveOperation();
        } finally {
          developer.Timeline.finishSync();
        }
      },
      child: Text('Test Performance'),
    );
  }

  void performExpensiveOperation() {
    // Your code here
  }
}

Memory Leak Detection:

dart
// Check for memory leaks
class LeakDetection extends StatefulWidget {
  
  _LeakDetectionState createState() => _LeakDetectionState();
}

class _LeakDetectionState extends State<LeakDetection> {
  StreamSubscription? _subscription;

  
  void initState() {
    super.initState();
    _subscription = someStream.listen((data) {
      // Handle data
    });
  }

  
  void dispose() {
    // ✅ Always dispose subscriptions
    _subscription?.cancel();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return Container();
  }
}

5. State Management Analysis

Debug State Changes:

dart
// With Provider
class DebugNotifier extends ChangeNotifier {
  int _count = 0;

  int get count => _count;

  void increment() {
    debugPrint('Before increment: $_count');
    _count++;
    debugPrint('After increment: $_count');
    notifyListeners();
    debugPrint('Listeners notified');
  }
}

// With Bloc
class DebugBloc extends Bloc<CounterEvent, CounterState> {
  DebugBloc() : super(CounterInitial()) {
    on<IncrementEvent>((event, emit) {
      debugPrint('Event received: $event');
      debugPrint('Current state: $state');
      emit(CounterState(count: state.count + 1));
      debugPrint('New state emitted: $state');
    });
  }

  
  void onChange(Change<CounterState> change) {
    super.onChange(change);
    debugPrint('State changed: ${change.currentState}${change.nextState}');
  }
}

6. Network Analysis

Debug API Calls:

dart
class ApiDebugger {
  static Future<http.Response> debugRequest(
    String url,
    Map<String, String>? headers,
  ) async {
    debugPrint('=== API REQUEST ===');
    debugPrint('URL: $url');
    debugPrint('Headers: $headers');

    final stopwatch = Stopwatch()..start();

    try {
      final response = await http.get(Uri.parse(url), headers: headers);
      stopwatch.stop();

      debugPrint('=== API RESPONSE ===');
      debugPrint('Status: ${response.statusCode}');
      debugPrint('Time: ${stopwatch.elapsedMilliseconds}ms');
      debugPrint('Body length: ${response.body.length}');

      return response;
    } catch (e) {
      stopwatch.stop();
      debugPrint('=== API ERROR ===');
      debugPrint('Error: $e');
      debugPrint('Time: ${stopwatch.elapsedMilliseconds}ms');
      rethrow;
    }
  }
}

7. UI/Layout Analysis

Debug Paint:

dart
void main() {
  // Enable debug paint
  debugPaintSizeEnabled = true;
  debugPaintBaselinesEnabled = true;
  debugPaintPointersEnabled = true;

  runApp(MyApp());
}

Layout Debugging:

dart
// Catch overflow errors
class SafeContainer extends StatelessWidget {
  final Widget child;

  const SafeContainer({required this.child});

  
  Widget build(BuildContext context) {
    return Container(
      child: LayoutBuilder(
        builder: (context, constraints) {
          debugPrint('Available constraints: $constraints');
          return child;
        },
      ),
    );
  }
}

8. Comprehensive Bug Analysis Checklist

AngleWhat to CheckTools
CodeNull safety, logic errorsStatic analysis, IDE
PerformanceFrame drops, jankPerformance overlay, Timeline
MemoryLeaks, excessive usageDevTools Memory
NetworkAPI failures, timeoutsNetwork inspector
StateIncorrect state transitionsState logging
UILayout issues, overflowDebug paint, Inspector
PlatformPlatform-specific bugsPlatform channels
DependenciesVersion conflicts
text
flutter pub outdated

9. Logging Strategy

dart
enum LogLevel { debug, info, warning, error }

class BugLogger {
  static void log(
    String message, {
    LogLevel level = LogLevel.info,
    String? tag,
    dynamic error,
    StackTrace? stackTrace,
  }) {
    final timestamp = DateTime.now().toIso8601String();
    final prefix = '[${level.name.toUpperCase()}]';
    final tagStr = tag != null ? '[$tag]' : '';

    debugPrint('$timestamp $prefix$tagStr $message');

    if (error != null) {
      debugPrint('Error: $error');
    }

    if (stackTrace != null) {
      debugPrint('StackTrace:
$stackTrace');
    }
  }
}

// Usage
BugLogger.log(
  'Failed to load user data',
  level: LogLevel.error,
  tag: 'ProfileScreen',
  error: e,
  stackTrace: stackTrace,
);

10. Bug Prevention Practices

  • Write unit tests for critical logic
  • Use const constructors to catch build-time errors
  • Enable strict null safety
  • Use linters (flutter_lints)
  • Implement error boundaries
  • Add assertions for assumptions
  • Document edge cases
  • Review code regularly

Important: Systematic bug analysis combines multiple tools and perspectives. Don't rely on just one method - investigate from code, performance, UI, and user experience angles.

Learn more at Flutter Debugging Guide.