LearnThatStack Ace your next interview

Flutter.
Interview cheat sheet.

Quick reference for Flutter - sectioned for fast scanning. Skim the part you're shaky on, walk in confident.

Mobile Development 21-section reference ~13 min read

Overview

Flutter is Google's open-source UI software development kit for building natively compiled applications from a single codebase. Released in 2017, it has revolutionized cross-platform development with its reactive framework, rich widget library, and exceptional performance through direct compilation to native ARM code.

1. Flutter Fundamentals

Why Flutter?

  • True Single Codebase: One codebase for iOS, Android, Web, Windows, macOS, Linux
  • Native Performance: Compiles to ARM/x64 machine code
  • Hot Reload: See changes instantly without losing state
  • Rich Widget Library: 100+ customizable widgets
  • Reactive Framework: UI rebuilds automatically when state changes
  • Strong Ecosystem: Pub.dev with 30,000+ packages

Flutter Architecture

┌─────────────────┐
│   Your App      │
├─────────────────┤
│  Flutter SDK    │
├─────────────────┤
│  Dart Runtime   │
├─────────────────┤
│  Skia Engine    │
├─────────────────┤
│Platform Channel │
└─────────────────┘

2. Dart Language Essentials

Variables & Types

// Type inference
var name = 'Flutter';
// Explicit type
String framework = 'Flutter';
// Final (runtime constant)
final currentTime = DateTime.now();
// Const (compile-time constant)
const pi = 3.14;
// Nullable types
String? nullable = null;
// Late initialization
late String lateVar;

Functions

// Named parameters
void greet({required String name, int age = 18}) {
  print('Hello $name, age: $age');
}

// Arrow functions
int add(int a, int b) => a + b;

// Anonymous functions
var multiply = (int a, int b) => a * b;

Classes & OOP

class Person {
  String name;
  int _age; // Private variable
  
  // Constructor
  Person(this.name, this._age);
  
  // Named constructor
  Person.guest() : name = 'Guest', _age = 0;
  
  // Getter
  int get age => _age;
  
  // Method
  void introduce() => print('I am $name');
}

// Inheritance
class Student extends Person {
  String school;
  
  Student(String name, int age, this.school) : super(name, age);
}

// Mixin
mixin Swimming {
  void swim() => print('Swimming');
}

class Athlete extends Person with Swimming {
  Athlete(String name, int age) : super(name, age);
}

3. Widgets

Stateless Widget

class MyCard extends StatelessWidget {
  final String title;
  
  const MyCard({Key? key, required this.title}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return Card(
      child: Text(title),
    );
  }
}

Stateful Widget

class Counter extends StatefulWidget {
  @override
  _CounterState createState() => _CounterState();
}

class _CounterState extends State<Counter> {
  int _count = 0;
  
  void _increment() {
    setState(() {
      _count++;
    });
  }
  
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('Count: $_count'),
        ElevatedButton(
          onPressed: _increment,
          child: Text('Increment'),
        ),
      ],
    );
  }
}

Widget Lifecycle (Stateful)

  1. createState() - Called once when widget is inserted
  2. initState() - Called once after createState
  3. didChangeDependencies() - Called when dependencies change
  4. build() - Called whenever widget needs to render
  5. didUpdateWidget() - Called when widget configuration changes
  6. setState() - Triggers rebuild
  7. deactivate() - Called when widget is removed from tree
  8. dispose() - Called when widget is permanently removed

4. Common Widgets

Layout Widgets

// Column (vertical)
Column(
  mainAxisAlignment: MainAxisAlignment.center,
  crossAxisAlignment: CrossAxisAlignment.start,
  children: [Widget1(), Widget2()],
)

// Row (horizontal)
Row(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: [Widget1(), Widget2()],
)

// Stack (overlapping)
Stack(
  alignment: Alignment.center,
  children: [
    Background(),
    Positioned(top: 10, left: 10, child: Icon()),
  ],
)

// Container
Container(
  padding: EdgeInsets.all(16),
  margin: EdgeInsets.symmetric(horizontal: 8),
  decoration: BoxDecoration(
    color: Colors.blue,
    borderRadius: BorderRadius.circular(8),
  ),
  child: Text('Hello'),
)

// Expanded & Flexible
Row(
  children: [
    Expanded(flex: 2, child: Widget1()),
    Expanded(flex: 1, child: Widget2()),
  ],
)

Scrollable Widgets

// ListView
ListView.builder(
  itemCount: items.length,
  itemBuilder: (context, index) => ListTile(
    title: Text(items[index]),
  ),
)

// GridView
GridView.count(
  crossAxisCount: 2,
  children: List.generate(6, (i) => Card(child: Text('$i'))),
)

// SingleChildScrollView
SingleChildScrollView(
  child: Column(children: widgets),
)

5. State Management

setState (Local State)

setState(() {
  _counter++;
});

InheritedWidget

class MyInheritedWidget extends InheritedWidget {
  final int data;
  
  MyInheritedWidget({required this.data, required Widget child}) 
    : super(child: child);
  
  static MyInheritedWidget? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();
  }
  
  @override
  bool updateShouldNotify(MyInheritedWidget old) => data != old.data;
}

Provider Pattern

// Model
class CounterModel extends ChangeNotifier {
  int _count = 0;
  int get count => _count;
  
  void increment() {
    _count++;
    notifyListeners();
  }
}

// Usage
Provider<CounterModel>(
  create: (_) => CounterModel(),
  child: MyApp(),
)

// Consumer
Consumer<CounterModel>(
  builder: (context, counter, child) => Text('${counter.count}'),
)

// Provider.of
final counter = Provider.of<CounterModel>(context);

BLoC Pattern (Business Logic Component)

// Event
abstract class CounterEvent {}
class Increment extends CounterEvent {}

// State
class CounterState {
  final int count;
  CounterState(this.count);
}

// BLoC
class CounterBloc extends Bloc<CounterEvent, CounterState> {
  CounterBloc() : super(CounterState(0));
  
  @override
  Stream<CounterState> mapEventToState(CounterEvent event) async* {
    if (event is Increment) {
      yield CounterState(state.count + 1);
    }
  }
}

6. Navigation & Routing

Basic Navigation

// Push
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => SecondScreen()),
);

// Pop
Navigator.pop(context);

// Push and remove all
Navigator.pushAndRemoveUntil(
  context,
  MaterialPageRoute(builder: (context) => HomeScreen()),
  (route) => false,
);

Named Routes

// Define routes
MaterialApp(
  routes: {
    '/': (context) => HomeScreen(),
    '/details': (context) => DetailsScreen(),
  },
)

// Navigate
Navigator.pushNamed(context, '/details');

// With arguments
Navigator.pushNamed(
  context, 
  '/details',
  arguments: {'id': 123},
);

// Receive arguments
final args = ModalRoute.of(context)!.settings.arguments as Map;

7. Async Programming

Future

Future<String> fetchData() async {
  await Future.delayed(Duration(seconds: 2));
  return 'Data loaded';
}

// Usage
void loadData() async {
  try {
    final data = await fetchData();
    print(data);
  } catch (e) {
    print('Error: $e');
  }
}

// FutureBuilder
FutureBuilder<String>(
  future: fetchData(),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      return CircularProgressIndicator();
    }
    if (snapshot.hasError) {
      return Text('Error: ${snapshot.error}');
    }
    return Text(snapshot.data ?? '');
  },
)

Stream

Stream<int> countStream() async* {
  for (int i = 0; i < 5; i++) {
    await Future.delayed(Duration(seconds: 1));
    yield i;
  }
}

// StreamBuilder
StreamBuilder<int>(
  stream: countStream(),
  builder: (context, snapshot) {
    if (snapshot.hasData) {
      return Text('Count: ${snapshot.data}');
    }
    return Text('Waiting...');
  },
)

8. HTTP & APIs

Using http package

import 'package:http/http.dart' as http;
import 'dart:convert';

Future<List<User>> fetchUsers() async {
  final response = await http.get(
    Uri.parse('https://api.example.com/users'),
    headers: {'Authorization': 'Bearer token'},
  );
  
  if (response.statusCode == 200) {
    final List<dynamic> data = json.decode(response.body);
    return data.map((json) => User.fromJson(json)).toList();
  } else {
    throw Exception('Failed to load users');
  }
}

// POST request
Future<void> createUser(User user) async {
  final response = await http.post(
    Uri.parse('https://api.example.com/users'),
    headers: {'Content-Type': 'application/json'},
    body: json.encode(user.toJson()),
  );
}

9. Local Storage

SharedPreferences

// Save
final prefs = await SharedPreferences.getInstance();
await prefs.setString('username', 'John');
await prefs.setInt('age', 25);
await prefs.setBool('isLoggedIn', true);

// Read
final username = prefs.getString('username') ?? '';
final age = prefs.getInt('age') ?? 0;
final isLoggedIn = prefs.getBool('isLoggedIn') ?? false;

// Remove
await prefs.remove('username');

SQLite

// Database helper
class DatabaseHelper {
  static Database? _database;
  
  Future<Database> get database async {
    if (_database != null) return _database!;
    _database = await _initDB();
    return _database!;
  }
  
  Future<Database> _initDB() async {
    String path = join(await getDatabasesPath(), 'app.db');
    return await openDatabase(
      path,
      version: 1,
      onCreate: (db, version) async {
        await db.execute('''
          CREATE TABLE users(
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT,
            age INTEGER
          )
        ''');
      },
    );
  }
  
  Future<int> insertUser(Map<String, dynamic> user) async {
    Database db = await database;
    return await db.insert('users', user);
  }
}

10. Forms & Validation

class LoginForm extends StatefulWidget {
  @override
  _LoginFormState createState() => _LoginFormState();
}

class _LoginFormState extends State<LoginForm> {
  final _formKey = GlobalKey<FormState>();
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();
  
  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        children: [
          TextFormField(
            controller: _emailController,
            decoration: InputDecoration(labelText: 'Email'),
            validator: (value) {
              if (value == null || value.isEmpty) {
                return 'Please enter email';
              }
              if (!value.contains('@')) {
                return 'Please enter valid email';
              }
              return null;
            },
          ),
          TextFormField(
            controller: _passwordController,
            obscureText: true,
            decoration: InputDecoration(labelText: 'Password'),
            validator: (value) {
              if (value == null || value.length < 6) {
                return 'Password must be at least 6 characters';
              }
              return null;
            },
          ),
          ElevatedButton(
            onPressed: () {
              if (_formKey.currentState!.validate()) {
                // Process data
              }
            },
            child: Text('Submit'),
          ),
        ],
      ),
    );
  }
  
  @override
  void dispose() {
    _emailController.dispose();
    _passwordController.dispose();
    super.dispose();
  }
}

11. Animations

Implicit Animations

// AnimatedContainer
AnimatedContainer(
  duration: Duration(seconds: 1),
  width: _expanded ? 200 : 100,
  height: _expanded ? 200 : 100,
  color: _expanded ? Colors.blue : Colors.red,
  child: Text('Tap me'),
)

// AnimatedOpacity
AnimatedOpacity(
  opacity: _visible ? 1.0 : 0.0,
  duration: Duration(milliseconds: 500),
  child: Text('Fade me'),
)

Explicit Animations

class _MyAnimationState extends State<MyAnimation> 
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;
  
  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: Duration(seconds: 2),
      vsync: this,
    );
    _animation = Tween<double>(begin: 0, end: 300).animate(
      CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
    );
    _controller.forward();
  }
  
  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _animation,
      builder: (context, child) {
        return Container(
          width: _animation.value,
          height: _animation.value,
          color: Colors.blue,
        );
      },
    );
  }
  
  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}

12. Platform-Specific Code

Platform Channels

// Flutter side
class BatteryLevel {
  static const platform = MethodChannel('com.example.app/battery');
  
  Future<int> getBatteryLevel() async {
    try {
      final int result = await platform.invokeMethod('getBatteryLevel');
      return result;
    } catch (e) {
      return -1;
    }
  }
}

// Check platform
import 'dart:io';

if (Platform.isAndroid) {
  // Android specific code
} else if (Platform.isIOS) {
  // iOS specific code
}

13. Testing

Unit Testing

// Test file: test/calculator_test.dart
import 'package:test/test.dart';

void main() {
  group('Calculator', () {
    test('addition', () {
      expect(add(2, 3), 5);
    });
    
    test('subtraction', () {
      expect(subtract(5, 3), 2);
    });
  });
}

Widget Testing

import 'package:flutter_test/flutter_test.dart';

void main() {
  testWidgets('Counter increments', (WidgetTester tester) async {
    await tester.pumpWidget(MyApp());
    
    // Find widgets
    expect(find.text('0'), findsOneWidget);
    expect(find.text('1'), findsNothing);
    
    // Tap button
    await tester.tap(find.byIcon(Icons.add));
    await tester.pump();
    
    // Verify
    expect(find.text('0'), findsNothing);
    expect(find.text('1'), findsOneWidget);
  });
}

14. Performance Best Practices

Keys

// Use keys for widget identity
ListView.builder(
  itemBuilder: (context, index) => MyWidget(
    key: ValueKey(items[index].id),
    data: items[index],
  ),
)

const Constructors

// Use const for compile-time constants
const Text('Hello World')
const EdgeInsets.all(16.0)
const SizedBox(height: 20)

Build Optimization

// Avoid rebuilding in build method
class BadExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // DON'T: Create new objects in build
    final data = expensiveComputation(); // Bad!
    return Text(data);
  }
}

class GoodExample extends StatefulWidget {
  @override
  _GoodExampleState createState() => _GoodExampleState();
}

class _GoodExampleState extends State<GoodExample> {
  late String data;
  
  @override
  void initState() {
    super.initState();
    // DO: Initialize expensive operations once
    data = expensiveComputation(); // Good!
  }
  
  @override
  Widget build(BuildContext context) {
    return Text(data);
  }
}

15. Critical Interview Topics

Widget Types - Deep Understanding

StatelessWidget:

  • Immutable configuration
  • No internal state management
  • Rebuilds only when parent rebuilds
  • Performance: More efficient for static content
  • Example: Icons, Labels, Containers with fixed content

StatefulWidget:

  • Maintains mutable state
  • Two classes: Widget (immutable) + State (mutable)
  • Can trigger its own rebuilds via setState()
  • Lifecycle methods available
  • Example: Forms, Animations, Dynamic lists

BuildContext Explained

// BuildContext is your widget's GPS in the widget tree
// It provides:
// 1. Location in tree
// 2. Access to inherited widgets
// 3. Theme and MediaQuery data

// Common uses:
Theme.of(context).primaryColor
MediaQuery.of(context).size
Navigator.of(context).push()
Scaffold.of(context).showSnackBar()

Hot Reload vs Hot Restart vs Full Restart

Feature Hot Reload Hot Restart Full Restart
State Preservation Yes No No
Speed <1 second 2-5 seconds 10-30 seconds
Recompiles Modified files All Dart code Everything
Use Case UI tweaks Logic changes Native code changes
Shortcut r R Stop + Run

Layout Understanding - Constraints Go Down, Sizes Go Up

Flutter's Golden Rule:
"Constraints go down. Sizes go up. Parent sets position."

MainAxis vs CrossAxis:

// Column: mainAxis = vertical, crossAxis = horizontal
Column(
  mainAxisAlignment: MainAxisAlignment.center,    // Vertical
  crossAxisAlignment: CrossAxisAlignment.start,   // Horizontal
  children: [...],
)

// Row: mainAxis = horizontal, crossAxis = vertical
Row(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,  // Horizontal
  crossAxisAlignment: CrossAxisAlignment.center,     // Vertical
  children: [...],
)

Async Patterns - FutureBuilder vs StreamBuilder

Aspect FutureBuilder StreamBuilder
Data Type Future Stream
Updates Once Multiple times
Use Cases HTTP requests, File I/O Real-time data, WebSockets
State Management ConnectionState AsyncSnapshot
Memory Disposed after complete Needs manual disposal
// FutureBuilder - One-time fetch
FutureBuilder<User>(
  future: fetchUser(),  // Called once
  builder: (context, snapshot) {
    if (snapshot.hasData) return UserWidget(snapshot.data!);
    if (snapshot.hasError) return ErrorWidget();
    return LoadingWidget();
  },
)

// StreamBuilder - Continuous updates
StreamBuilder<List<Message>>(
  stream: chatStream(),  // Continuous emission
  builder: (context, snapshot) {
    // Rebuilds on every stream event
  },
)

Responsive Design Strategies

1. MediaQuery Approach:

class ResponsiveWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final size = MediaQuery.of(context).size;
    final orientation = MediaQuery.of(context).orientation;
    final padding = MediaQuery.of(context).padding;
    
    // Breakpoints
    final isMobile = size.width < 600;
    final isTablet = size.width >= 600 && size.width < 1200;
    final isDesktop = size.width >= 1200;
    
    return Container(
      width: isMobile ? double.infinity : 600,
      padding: EdgeInsets.all(isMobile ? 16 : 32),
    );
  }
}

2. LayoutBuilder for Adaptive Layouts:

LayoutBuilder(
  builder: (context, constraints) {
    // Responsive grid
    int crossAxisCount = constraints.maxWidth < 600 ? 2 : 
                         constraints.maxWidth < 900 ? 3 : 4;
    
    return GridView.builder(
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: crossAxisCount,
      ),
      itemBuilder: (context, index) => Card(),
    );
  },
)

3. Platform-Adaptive Components:

// Adaptive widgets that look native on each platform
import 'package:flutter/cupertino.dart';

Switch.adaptive()      // Material on Android, Cupertino on iOS
Slider.adaptive()
CircularProgressIndicator.adaptive()

Keys - The Complete Guide

When to Use Keys:

  1. Reordering lists with stateful children
  2. Animating widget additions/removals
  3. Preserving scroll position
  4. Maintaining form field state

Types of Keys:

// ValueKey - When you have a unique primitive value
ListTile(key: ValueKey(item.id))

// ObjectKey - For complex objects
Widget(key: ObjectKey(person))

// UniqueKey - New key every time
AnimatedWidget(key: UniqueKey())

// GlobalKey - Access widget state/context from anywhere
final _scaffoldKey = GlobalKey<ScaffoldState>();
_scaffoldKey.currentState?.showSnackBar();

// PageStorageKey - Preserve scroll position
ListView(key: PageStorageKey('list_key'))

Common Mistake:

// WRONG - Key on wrong widget level
Padding(
  padding: EdgeInsets.all(8),
  child: Container(key: ValueKey(item.id)),
)

// CORRECT - Key at the right level
Padding(
  key: ValueKey(item.id),
  padding: EdgeInsets.all(8),
  child: Container(),
)

Memory Management Best Practices

1. Proper Disposal Pattern:

class _MyWidgetState extends State<MyWidget> {
  late AnimationController _animationController;
  late TextEditingController _textController;
  late ScrollController _scrollController;
  StreamSubscription? _subscription;
  Timer? _timer;
  
  @override
  void initState() {
    super.initState();
    _animationController = AnimationController(vsync: this);
    _textController = TextEditingController();
    _scrollController = ScrollController();
    _subscription = stream.listen((data) {});
    _timer = Timer.periodic(Duration(seconds: 1), (timer) {});
  }
  
  @override
  void dispose() {
    // Dispose in reverse order of initialization
    _timer?.cancel();
    _subscription?.cancel();
    _scrollController.dispose();
    _textController.dispose();
    _animationController.dispose();
    super.dispose();  // Always call super.dispose() last
  }
}

2. Common Memory Leak Causes:

  • Not disposing controllers
  • Keeping references to disposed contexts
  • Uncancelled timers/animations
  • Stream subscriptions without cancellation
  • GlobalKeys holding state references
  • Circular references in closures

3. Detection Tools:

  • Flutter Inspector's memory profiler
  • Dart DevTools memory view
  • LeakCanary for platform-specific leaks

16. Common Patterns & Tips

Null Safety

// Null-aware operators
String? name;
print(name ?? 'Default');  // Default if null
print(name?.length);       // Null if name is null
name ??= 'John';          // Assign if null

// Late initialization
late String lateString;

Extension Methods

extension StringExtension on String {
  String capitalize() {
    return '${this[0].toUpperCase()}${substring(1)}';
  }
}

// Usage
'hello'.capitalize(); // 'Hello'

Factory Pattern

class Logger {
  static final Map<String, Logger> _cache = {};
  final String name;
  
  factory Logger(String name) {
    return _cache.putIfAbsent(name, () => Logger._internal(name));
  }
  
  Logger._internal(this.name);
}

Singleton Pattern

class DatabaseService {
  static final DatabaseService _instance = DatabaseService._internal();
  
  factory DatabaseService() => _instance;
  
  DatabaseService._internal();
}

17. Important Packages

  • state_management: provider, bloc, riverpod, getx
  • navigation: go_router, auto_route
  • networking: dio, http, retrofit
  • storage: shared_preferences, hive, sqflite
  • images: cached_network_image, image_picker
  • forms: flutter_form_builder
  • animations: lottie, rive
  • testing: mockito, flutter_test

18. Debug Tools & Commands

# Create new project
flutter create my_app

# Run app
flutter run

# Build APK
flutter build apk

# Build iOS
flutter build ios

# Run tests
flutter test

# Analyze code
flutter analyze

# Clean project
flutter clean

# Get packages
flutter pub get

# Upgrade packages
flutter pub upgrade

Debug Tools

  • Flutter Inspector
  • Performance Overlay
  • Debug Paint
  • Widget Inspector
  • Timeline View

Performance Optimization Checklist

Build Performance

  1. Use const constructors wherever possible
  2. Split widgets into smaller, reusable components
  3. Avoid rebuilding expensive widgets unnecessarily
  4. Use RepaintBoundary for complex graphics
  5. Implement itemExtent in ListView for better performance

State Management Performance

  1. Lift state up only as high as necessary
  2. Use ValueListenableBuilder for single value changes
  3. Avoid setState() in loops
  4. Use Selector (Provider) to rebuild only affected widgets

Image & Asset Optimization

// Cache network images
CachedNetworkImage(
  imageUrl: url,
  placeholder: (context, url) => CircularProgressIndicator(),
  errorWidget: (context, url, error) => Icon(Icons.error),
)

// Preload images
precacheImage(AssetImage('assets/background.png'), context);

// Use appropriate image formats
// WebP for photos (30% smaller)
// PNG for graphics with transparency
// SVG for scalable graphics

State Management Decision Tree

Local State? → setState
Ancestor Access? → InheritedWidget
Simple App? → Provider
Complex App? → BLoC/Riverpod

Performance Checklist

  • Use const constructors
  • Implement Keys correctly
  • Dispose controllers
  • Avoid rebuilding expensive widgets
  • Use ListView.builder for long lists
  • Cache network images
  • Minimize widget rebuilds

Common Gotchas

  1. Don't call setState() in build()
  2. Don't forget to dispose() controllers
  3. Use Keys when reordering widgets
  4. Avoid storing BuildContext
  5. Handle null safety properly

Interview Success Strategy

Technical Preparation

  1. Master the fundamentals: Widget lifecycle, BuildContext, Keys
  2. Practice live coding: Build a TODO app, Weather app, Chat UI
  3. Know performance optimization: Const widgets, Keys, RepaintBoundary
  4. Understand state management: setState, Provider, Riverpod, BLoC
  5. Platform-specific knowledge: Method channels, platform views

Common Code Challenges

  • Build a custom widget from scratch
  • Implement infinite scrolling list
  • Create a form with validation
  • Handle API calls with error states
  • Implement custom animations
  • Build responsive layouts

Red Flags to Avoid

  • Not using const constructors
  • Memory leaks from undisposed controllers
  • Rebuilding entire tree with setState
  • Network calls in build methods
  • Ignoring null safety
  • Poor error handling

Pro Tip: Flutter rewards composition over inheritance. When asked to solve a problem, think about combining existing widgets rather than creating complex inheritance hierarchies. Show your understanding of Flutter's declarative paradigm and reactive framework.

Found this useful? Pass it on.
Pro · $10/mo

The sheet is free. Pro goes deeper.

Pro opens the full question library behind every sheet, every refresher and a monthly AI allowance. One subscription, all formats.

Full question library All refreshers Cancel anytime