Skip to content
RED SAGSkills

Flutter interview questions and answers

Flutter questions cover widgets, state management and building smooth cross-platform apps with Dart.

Below are 47 Flutter questions with the correct answer and a short explanation, grouped from fresher to experienced level. Try each one before you open the answer.

What Flutter interviews usually check

  • ✓Stateless vs stateful widgets
  • ✓The widget tree and rebuilds
  • ✓State management options
  • ✓Async Dart and futures
  • ✓Performance and platform channels

Flutter interview questions for freshers easy

1. Flutter hot reload vs restart

You changed a text color inside a Flutter build method and want to see it while keeping the current screen and the counter value you already set. What should you use?

  1. A.Hot restart
  2. B.Hot reload
  3. C.A full rebuild and reinstall
  4. D.flutter clean, then run again
Show answer

Answer: B. Hot reload

Hot reload injects the changed code into the running Dart VM and rebuilds the widget tree while keeping State objects. Hot restart reruns the app from main() and resets all state. Changes to initState, global initializers or main() usually need a hot restart to take effect.

2. Dart final versus const

In Dart, what is the main difference between a `final` variable and a `const` variable?

  1. A.final must be known at compile time; const is set once at runtime
  2. B.const can be reassigned later; final can never change
  3. C.const must be known at compile time; final is set once at runtime
  4. D.There is no difference; both are aliases of var
Show answer

Answer: C. const must be known at compile time; final is set once at runtime

A `final` variable can be assigned only once, but its value may come from runtime work such as DateTime.now(). A `const` value must be a compile-time constant, and identical const values are canonicalised so they share one instance.

3. Reading the screen width

You need the available screen width inside a Flutter widget to switch between a phone and tablet layout. Which call gives it?

  1. A.Theme.of(context).width
  2. B.Navigator.of(context).size.width
  3. C.Scaffold.of(context).screenWidth
  4. D.MediaQuery.sizeOf(context).width
Show answer

Answer: D. MediaQuery.sizeOf(context).width

MediaQuery exposes the size, padding and text scale of the current window. MediaQuery.sizeOf(context) also makes the widget rebuild only when the size changes, not on every other MediaQuery change. For layout that depends on the parent box rather than the window, LayoutBuilder is the better tool.

4. ListView.builder for a long feed

A feed has 5,000 items. Why is ListView.builder preferred over ListView(children: [...])?

  1. A.It loads all 5,000 items in a background isolate first
  2. B.It builds only the items that are on or near the screen
  3. C.It caches every item as an image for faster scrolling
  4. D.It is the only ListView that supports scrolling
Show answer

Answer: B. It builds only the items that are on or near the screen

ListView(children: ...) needs every child widget created up front, which costs memory and startup time. ListView.builder calls itemBuilder lazily as items scroll into view, so cost stays proportional to what is visible.

5. Future or Stream

A chat screen must react to every new message that arrives over a socket. Which Dart type models this?

  1. A.A Future, because it delivers many values over time
  2. B.A Stream, because it delivers many values over time
  3. C.A List, because messages arrive in order
  4. D.A Completer, because it repeats automatically
Show answer

Answer: B. A Stream, because it delivers many values over time

A Future completes once with a single value or error. A Stream emits zero or more events over time and can then close, which fits a feed of messages. In Flutter, StreamBuilder rebuilds a widget for each new event.

6. Validating a Flutter form

A login screen uses a Form with two TextFormFields that have validators. How do you run all validators when Submit is tapped?

  1. A.Give the Form a GlobalKey<FormState> and call currentState!.validate()
  2. B.Call validate() on each TextEditingController in turn
  3. C.Wrap the whole form in a FutureBuilder and rebuild it
  4. D.Set autovalidateMode to disabled and then call setState
Show answer

Answer: A. Give the Form a GlobalKey<FormState> and call currentState!.validate()

A GlobalKey<FormState> gives access to the Form's State object. validate() runs every field validator, shows the error texts, and returns true only when all pass. save() can then call each field's onSaved.

7. Cleaning up a TextEditingController

A StatefulWidget creates a TextEditingController in initState. What should happen when the screen is removed?

  1. A.Nothing; Dart garbage collects it immediately
  2. B.Set the controller to null in build
  3. C.Call controller.dispose() in the State's dispose method
  4. D.Call controller.clear() in initState
Show answer

Answer: C. Call controller.dispose() in the State's dispose method

Controllers hold listeners and resources. Disposing them in dispose() releases those listeners and prevents leaks and "used after being disposed" errors. The same rule applies to AnimationController, FocusNode, ScrollController and stream subscriptions.

8. Animating a size change simply

A card should smoothly grow from 100 to 200 pixels tall when tapped, with no custom controller. Which widget fits best?

  1. A.CustomPainter with a Timer
  2. B.AnimationController with a Tween and a listener
  3. C.A Stack with two Containers
  4. D.AnimatedContainer with a duration
Show answer

Answer: D. AnimatedContainer with a duration

Implicit animation widgets such as AnimatedContainer, AnimatedOpacity and AnimatedAlign animate automatically from the old value to the new one whenever you rebuild them with different properties. You only set a duration and curve. Explicit controllers are needed for looping or fully controlled animations.

9. What flutter doctor reports

A new team member cannot build the app. What does running `flutter doctor` tell them?

  1. A.Which Dart files have lint warnings that block the build
  2. B.Which packages in pubspec.yaml have newer versions on pub.dev
  3. C.Whether the SDK, Android toolchain, Xcode and devices are set up
  4. D.How long each widget takes to build on the connected phone
Show answer

Answer: C. Whether the SDK, Android toolchain, Xcode and devices are set up

flutter doctor checks the local development environment: the Flutter and Dart SDKs, the Android SDK and licences, Xcode and CocoaPods on macOS, IDE plugins and connected devices. Each missing piece is listed with a hint on how to fix it. Lints come from flutter analyze and package updates from flutter pub outdated.

10. How Flutter and React Native draw UI

What is the key difference in how Flutter and React Native put UI on screen?

  1. A.Flutter uses native platform views; React Native paints into a canvas
  2. B.Both render HTML inside a hidden WebView on the device
  3. C.Flutter paints its own widgets; React Native renders native platform views
  4. D.Both convert their code into Swift and Kotlin at build time
Show answer

Answer: C. Flutter paints its own widgets; React Native renders native platform views

Flutter draws every pixel with its own engine (Impeller or Skia), so the UI looks the same on every platform and OS version. React Native maps components such as View and Text to real native views. That is why React Native picks up platform look and behaviour more directly, while Flutter offers tighter visual control.

11. Integer division in Dart

In Dart, what is the value of `7 ~/ 2`?

  1. A.3.5
  2. B.4
  3. C.1
  4. D.3
Show answer

Answer: D. 3

The ~/ operator performs integer division and truncates toward zero, so 7 ~/ 2 is 3. The / operator always returns a double, so 7 / 2 is 3.5. The remainder 1 comes from 7 % 2.

12. String interpolation with an expression

What does this Dart code print when items has 3 elements?

final items = ['a', 'b', 'c'];
print('You have ${items.length} items');
  1. A.You have $items.length items
  2. B.You have [a, b, c].length items
  3. C.You have 3 items
  4. D.You have items.length items
Show answer

Answer: C. You have 3 items

Dart string interpolation uses $name for a simple identifier and ${expression} for anything more, such as a property access. Writing $items.length would interpolate only items and then print ".length" literally. The braces make the whole expression evaluate first.

13. Required named parameters

What does `required` mean in this constructor?

class Header extends StatelessWidget {
  const Header({super.key, required this.title});
  final String title;
}
  1. A.Callers must pass title by name, or the code does not compile
  2. B.title defaults to an empty string when it is not passed
  3. C.title must be passed as the first positional argument
  4. D.title is checked at runtime and may still be null
Show answer

Answer: A. Callers must pass title by name, or the code does not compile

Named parameters in Dart are optional unless marked required. With required, the analyzer reports an error at any call site that leaves title out. This is common in widget constructors, where named arguments keep calls readable.

14. Material 3 theming from one colour

A designer gives one brand colour and wants a full, consistent Material 3 palette in Flutter. What is the simplest approach?

  1. A.Set the brand colour on every widget's color property
  2. B.Create 40 const Color fields and pick them by hand
  3. C.Use a CupertinoTheme with the brand colour
  4. D.ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: brand))
Show answer

Answer: D. ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: brand))

ColorScheme.fromSeed generates matching primary, secondary, surface and container colours, plus on- colours with good contrast, from a single seed. Passing brightness: Brightness.dark gives the matching dark scheme. Widgets then read colours from the theme instead of hard-coding them.

15. Platform-looking switches

You want a switch that looks like a Cupertino switch on iOS and a Material switch on Android. What is the quickest option?

  1. A.Switch with a custom thumbColor
  2. B.CupertinoSwitch on both platforms
  3. C.A Checkbox styled as a toggle
  4. D.Switch.adaptive
Show answer

Answer: D. Switch.adaptive

Several Material widgets have .adaptive constructors, such as Switch.adaptive, Slider.adaptive and CircularProgressIndicator.adaptive. They render the Cupertino version on Apple platforms and the Material one elsewhere. That gives a more native feel without writing two code paths.

16. Measuring test coverage in Flutter

How do you produce a coverage report from Flutter unit and widget tests?

  1. A.flutter build --coverage, which writes a report in the APK
  2. B.flutter run --profile, then open DevTools coverage
  3. C.dart compile coverage main.dart
  4. D.flutter test --coverage, which writes coverage/lcov.info
Show answer

Answer: D. flutter test --coverage, which writes coverage/lcov.info

flutter test --coverage writes an lcov.info file that tools such as genhtml, Codecov or SonarQube can render. Coverage shows which lines tests executed, not whether the assertions are meaningful. Generated files are often excluded from the report.

Flutter intermediate interview questions medium

17. const constructors in Flutter

Why does Flutter recommend const constructors such as const Text('Hello') wherever possible?

  1. A.const widgets are created once and reused, so Flutter can skip rebuilding them when the parent rebuilds
  2. B.const widgets are drawn only by the GPU
  3. C.const tells Flutter to paint the widget once into a cached bitmap and reuse that image on every later frame, even if its text changes
  4. D.Without const, a widget cannot be stateless
Show answer

Answer: A. const widgets are created once and reused, so Flutter can skip rebuilding them when the parent rebuilds

A const widget is a compile-time constant, so the same instance is reused across builds. When Flutter sees an identical widget instance during a rebuild, it can skip rebuilding that subtree. This cuts work in frequently rebuilt screens with very little effort.

18. FutureBuilder refetching on rebuild

What is the bug in this Flutter code?

@override
Widget build(BuildContext context) {
  return FutureBuilder<User>(
    future: api.fetchUser(),
    builder: (context, snapshot) => UserCard(snapshot.data),
  );
}
  1. A.FutureBuilder cannot be used inside build
  2. B.A new request starts on every rebuild; create the future once (for example in initState) and pass the stored future
  3. C.fetchUser must return a Stream, because FutureBuilder only listens during the first frame and ignores results that arrive later
  4. D.The builder function must be marked async
Show answer

Answer: B. A new request starts on every rebuild; create the future once (for example in initState) and pass the stored future

build can run many times, for example on theme changes or parent rebuilds. Calling fetchUser() inside it creates a new Future each time, which triggers repeated network calls and flicker back to the loading state. Store the Future in a field set in initState, or move loading into a state management layer.

19. Reading a late variable too early

A Dart class declares `late String token;` and a method reads `token` before any code has assigned it. What happens?

  1. A.A LateInitializationError is thrown at runtime
  2. B.The variable silently returns an empty string
  3. C.The analyzer refuses to compile the class
  4. D.The variable returns null because it is nullable
Show answer

Answer: A. A LateInitializationError is thrown at runtime

`late` tells the compiler you promise to assign the value before first use, so the null-safety check moves to runtime. If the promise is broken, reading the field throws LateInitializationError. Use a nullable type instead when the value can genuinely be missing.

20. Yellow and black overflow stripes

A Row with a long product name shows the debug message "A RenderFlex overflowed by 48 pixels on the right". What is the right fix?

  1. A.Increase the font size so Flutter recalculates the layout
  2. B.Wrap the whole Row in a Center widget
  3. C.Wrap the Text in Expanded or Flexible so it can shrink or wrap
  4. D.Switch the app to release mode, where overflow is ignored
Show answer

Answer: C. Wrap the Text in Expanded or Flexible so it can shrink or wrap

A Row gives its children unbounded width, so a long Text asks for more space than exists. Wrapping it in Expanded or Flexible gives it a bounded width, and the text can then wrap or use overflow: TextOverflow.ellipsis. In release mode the content is still clipped; only the stripes are hidden.

21. ListView inside a Column

Placing a ListView directly inside a Column throws "Vertical viewport was given unbounded height". What is the usual fix?

  1. A.Give the Column a mainAxisAlignment of center
  2. B.Replace the Column with a Stack
  3. C.Set the ListView physics to NeverScrollableScrollPhysics
  4. D.Wrap the ListView in Expanded so it gets the remaining height
Show answer

Answer: D. Wrap the ListView in Expanded so it gets the remaining height

A Column lets its children be as tall as they want, and a ListView wants infinite height to scroll. Expanded gives the list a finite height equal to the leftover space. shrinkWrap: true also silences the error, but it lays out every item and loses the lazy-building benefit.

22. Caret version range in pubspec

pubspec.yaml contains `http: ^1.2.0`. Which versions can pub pick?

  1. A.Any version from 1.2.0 up to, but not including, 2.0.0
  2. B.Exactly 1.2.0 and nothing else
  3. C.Any version from 1.2.0 up to, but not including, 1.3.0
  4. D.Any version at all, including 2.x and later
Show answer

Answer: A. Any version from 1.2.0 up to, but not including, 2.0.0

The caret syntax allows versions that are backward compatible under semantic versioning, so for ^1.2.0 it means >=1.2.0 <2.0.0. For a 0.x package the rule is tighter: ^0.4.1 means >=0.4.1 <0.5.0, because a minor bump before 1.0 may break things.

23. Reusing behaviour with a mixin

Several unrelated widgets' State classes need the same logging helpers. What does `class _HomeState extends State<Home> with LoggerMixin` do?

  1. A.It makes LoggerMixin the parent class of State
  2. B.It creates a separate LoggerMixin object inside each State
  3. C.It lets _HomeState implement LoggerMixin with no method bodies
  4. D.It copies LoggerMixin's members into _HomeState without a second superclass
Show answer

Answer: D. It copies LoggerMixin's members into _HomeState without a second superclass

Dart has single inheritance, but `with` applies one or more mixins, layering their fields and methods on top of the superclass. That is also how TickerProviderStateMixin adds vsync support to a State.

24. Factory constructor for a singleton

Why use a `factory` constructor in this Dart class?

class ApiClient {
  static final ApiClient _instance = ApiClient._internal();
  factory ApiClient() => _instance;
  ApiClient._internal();
}
  1. A.It can return an existing instance instead of always creating a new one
  2. B.It makes the constructor body run on a separate background isolate
  3. C.It is required for any class that declares a static field
  4. D.It makes every field of the class const automatically
Show answer

Answer: A. It can return an existing instance instead of always creating a new one

A generative constructor always creates a new object. A factory constructor is a normal function body that may return a cached instance, a subtype, or an object built from JSON. Here every call to ApiClient() returns the same instance.

25. Calling native code from Flutter

A Flutter app needs a value from an Android-only SDK that has no plugin. What is the standard mechanism?

  1. A.A MethodChannel that calls Kotlin code and returns the result asynchronously
  2. B.A dart:html import that runs the Kotlin SDK code directly
  3. C.A const constructor that statically links the native library
  4. D.A new isolate that loads the whole Android SDK into Dart memory
Show answer

Answer: A. A MethodChannel that calls Kotlin code and returns the result asynchronously

Platform channels pass messages between Dart and the host platform. With a MethodChannel, Dart calls invokeMethod and awaits a Future, while Kotlin or Swift registers a handler and replies with a result or error. Arguments must use the standard codec types, such as maps, lists, strings and numbers.

26. Passing config with dart-define

A build uses `--dart-define=API_URL=https://staging.example.com`. How does Dart code read it?

  1. A.const String.fromEnvironment('API_URL')
  2. B.Platform.environment['API_URL'] at runtime
  3. C.dotenv.load() from the device file system
  4. D.It cannot be read; it only configures Gradle
Show answer

Answer: A. const String.fromEnvironment('API_URL')

Values passed with --dart-define (or --dart-define-from-file) are compile-time constants read with String.fromEnvironment, bool.fromEnvironment or int.fromEnvironment. They are baked into the binary, so they are fine for URLs and flags but not for secrets.

27. Adding Flutter to an existing app

A bank has a large native Android and iOS app and wants to build one new loan module in Flutter. What is the supported approach?

  1. A.Rewriting the whole app in Flutter before shipping anything
  2. B.Loading the Flutter module inside a WebView on each screen
  3. C.Shipping the loan module as a separate store app only
  4. D.Add-to-app, embedding a Flutter module inside the native apps
Show answer

Answer: D. Add-to-app, embedding a Flutter module inside the native apps

Flutter's add-to-app support packages a Flutter module as a library that native code launches through a FlutterEngine and FlutterActivity or FlutterViewController. Pre-warming and caching the engine avoids a delay when the screen opens. It allows gradual adoption without a rewrite.

28. What an async* function returns

What does this function return?

Stream<int> countdown() async* {
  for (var i = 1; i <= 3; i++) {
    await Future.delayed(const Duration(seconds: 1));
    yield i;
  }
}
  1. A.A Future<int> that completes with 3 after three seconds
  2. B.A Stream<int> that emits 1, 2 and 3 with a second between them
  3. C.A List<int> containing 1, 2 and 3 straight away
  4. D.A Future<List<int>> that completes once with all values
Show answer

Answer: B. A Stream<int> that emits 1, 2 and 3 with a second between them

A function marked async* is an asynchronous generator. Each yield adds an event to the returned Stream, and await can pause between events. The stream closes when the function body ends.

29. Closing a StreamController

A ViewModel class creates a StreamController for search results. What should its dispose method do?

  1. A.Call controller.close() so listeners finish and get freed
  2. B.Set the controller to null and let it keep running
  3. C.Call controller.add(null) as the very last event
  4. D.Nothing; streams close by themselves on every rebuild
Show answer

Answer: A. Call controller.close() so listeners finish and get freed

An open StreamController keeps its listeners and buffered events alive. Closing it sends a done event, lets StreamBuilder and subscriptions finish, and avoids memory leaks. Subscriptions you create with listen should also be cancelled.

30. Protecting routes with go_router

With go_router, logged-out users who open /orders should be sent to /login. Where is this best handled?

  1. A.In every screen's build method with a Navigator.push
  2. B.In the router's redirect callback, based on the auth state
  3. C.In main() before runApp, by checking the URL once
  4. D.In the AndroidManifest.xml intent filters
Show answer

Answer: B. In the router's redirect callback, based on the auth state

go_router calls redirect before showing any route, including deep links. Returning '/login' when there is no session, and null otherwise, guards every route in one place. Passing a refreshListenable re-runs it when the auth state changes.

31. Localizing a Flutter app

How does a Flutter app typically handle English and Arabic strings?

  1. A.ARB files per locale, generated into an AppLocalizations class
  2. B.An if statement around every Text widget in the app
  3. C.A JSON file read from the server on each screen
  4. D.Separate Git branches for each of the languages
Show answer

Answer: A. ARB files per locale, generated into an AppLocalizations class

With flutter_localizations and gen-l10n, translators edit app_en.arb and app_ar.arb, and Flutter generates a typed AppLocalizations class. ICU syntax handles plurals and placeholders. For Arabic, Directionality switches to right-to-left automatically when the locale is set.

32. setState called during build

A widget calls `setState(() => count++)` directly inside its build method and the app shows "setState() or markNeedsBuild() called during build". Why is this wrong?

  1. A.build must not change state, or rebuilds would loop
  2. B.setState is only allowed inside a StatelessWidget
  3. C.count must be declared as a const value first
  4. D.setState needs to be awaited inside build
Show answer

Answer: A. build must not change state, or rebuilds would loop

build should describe the UI from the current state, with no side effects. Changing state there would schedule another build while one is running, risking an endless loop. Move the change to an event handler or initState, or use addPostFrameCallback if it must follow a frame.

Flutter interview questions for experienced candidates hard

33. Swapped Flutter tiles keep colors

Two StatefulWidget tiles in a Row store a random color in their State. When you swap their order in the list, the colors do not move with them. Why?

  1. A.Flutter matches widgets to existing elements by type and position, so without keys the State objects stay in place; give each tile a key such as ValueKey(tile.id)
  2. B.setState was not called after the swap
  3. C.Row caches the first children it was given and keeps painting them, so a reordered list is ignored until the screen is pushed again
  4. D.StatefulWidgets cannot be reordered in Flutter
Show answer

Answer: A. Flutter matches widgets to existing elements by type and position, so without keys the State objects stay in place; give each tile a key such as ValueKey(tile.id)

When rebuilding, Flutter compares the new widget list with the existing elements, and same-type widgets in the same slot reuse the old element and its State. After the swap, each slot still has the same type, so the States stay where they were. Keys let Flutter match by identity, so the State moves with its widget.

34. Dart microtask and event order

In what order does this Dart program print its letters?

import 'dart:async';

void main() {
  print('A');
  Future(() => print('B'));
  scheduleMicrotask(() => print('C'));
  Future.value().then((_) => print('D'));
  print('E');
}
  1. A.A B C D E
  2. B.A E B C D
  3. C.A E C D B
  4. D.A C D E B
Show answer

Answer: C. A E C D B

Synchronous code runs first, printing A and E. Then the microtask queue is drained before the next event: C was queued first, then the completion of Future.value() runs the then callback, printing D. Future(() => ...) schedules a timer event, so B prints last.

35. Widget, element and render trees

Flutter keeps three trees: widgets, elements and render objects. Which statement about them is correct?

  1. A.Widgets are long-lived and mutable; elements are rebuilt from scratch on every frame
  2. B.Render objects are created again for every build, while elements are never reused
  3. C.Only the widget tree exists at runtime; the other two are debug-only views
  4. D.Widgets are cheap immutable configs; elements are long-lived and link widgets to render objects
Show answer

Answer: D. Widgets are cheap immutable configs; elements are long-lived and link widgets to render objects

Widgets are lightweight, immutable descriptions that are rebuilt often. Elements are the long-lived instances in the tree that hold State and decide whether to update or replace a render object. Render objects do layout and painting and are reused when the widget type and key match.

36. Overriding == without hashCode

A Product class overrides `operator ==` to compare ids but does not override `hashCode`. Two products with the same id are added to a Set. What is likely?

  1. A.The Set throws a runtime error because hashCode is missing
  2. B.The Set always keeps only one product, since == is checked first
  3. C.The Set may keep both, because equal objects have different hash codes
  4. D.The analyzer refuses to compile the Set literal with these objects
Show answer

Answer: C. The Set may keep both, because equal objects have different hash codes

Hash-based collections first use hashCode to pick a bucket and only then call ==. If equal objects can have different hash codes, they land in different buckets and the duplicate is never found. Always override both together, or use a package such as equatable or freezed.

37. Why teams use Pigeon

A team has dozens of MethodChannel calls with string method names and untyped maps, and bugs keep coming from typos. What does Pigeon offer?

  1. A.A faster rendering engine that replaces platform channels
  2. B.Automatic conversion of Kotlin code into Dart
  3. C.A way to share memory between Dart and native threads
  4. D.Generated, type-safe Dart, Kotlin and Swift code for the channel API
Show answer

Answer: D. Generated, type-safe Dart, Kotlin and Swift code for the channel API

Pigeon reads an interface definition written in Dart and generates matching host and Dart code for the messages. Method names and argument types are checked by each compiler, so mismatches show up at build time instead of as runtime MissingPluginException or cast errors.

38. Calling a C library from Dart

You need to call a fast C image-processing library synchronously from Dart on mobile. Which approach avoids platform-channel message overhead?

  1. A.A MethodChannel with a binary codec
  2. B.dart:ffi bindings to the compiled C library
  3. C.An EventChannel that streams pixels
  4. D.A WebView running the C code through WebAssembly
Show answer

Answer: B. dart:ffi bindings to the compiled C library

dart:ffi lets Dart call native C functions directly in the same process, without serialising messages to the platform side. Tools such as ffigen generate bindings from C headers. Long-running calls should still run on a background isolate so the UI does not freeze.

39. Reading the performance overlay

The Flutter performance overlay shows the raster (GPU) graph spiking red while the UI graph stays green. Where is the problem most likely?

  1. A.Slow Dart code running inside build methods
  2. B.Costly painting such as saveLayer, heavy clips or big blurs
  3. C.Too many network calls made from the UI isolate
  4. D.Slow JSON parsing inside a FutureBuilder callback
Show answer

Answer: B. Costly painting such as saveLayer, heavy clips or big blurs

The UI thread runs your Dart build, layout and paint recording. The raster thread turns the layer tree into GPU commands. When only raster time is high, the cost is in what is drawn, often opacity layers, clipping, shadows, blurs or oversized images, not in Dart logic.

40. shrinkWrap lists inside a scroll view

A screen nests five `ListView(shrinkWrap: true)` sections of 200 items each inside a SingleChildScrollView. Scrolling is slow. Why?

  1. A.shrinkWrap forces each of the lists to run on its own isolate
  2. B.SingleChildScrollView repaints only the first list it contains
  3. C.shrinkWrap lays out every item to measure the list, so nothing is lazy
  4. D.Nested lists disable hardware acceleration for the whole screen
Show answer

Answer: C. shrinkWrap lays out every item to measure the list, so nothing is lazy

With shrinkWrap the list must size itself to its content, so it builds and lays out all 1,000 items. Using a CustomScrollView with SliverList sections keeps one scroll viewport and builds only visible items.

41. Obfuscating a Flutter release

You build with `flutter build apk --obfuscate --split-debug-info=build/symbols`. What must you keep to read crash stack traces later?

  1. A.Nothing; obfuscated traces are readable by default
  2. B.The symbol files written to build/symbols for that exact build
  3. C.Only the AndroidManifest.xml of the build
  4. D.The debug APK built from the same commit
Show answer

Answer: B. The symbol files written to build/symbols for that exact build

Obfuscation renames Dart symbols, and split-debug-info moves the symbol tables out of the binary, which also reduces size. Stack traces then contain only addresses or obscured names. Running flutter symbolize with the matching symbols, or uploading them to your crash tool, turns them back into readable frames.

42. pumpAndSettle times out

A widget test calls `await tester.pumpAndSettle()` on a screen with a looping CircularProgressIndicator and fails with a timeout. What is the fix?

  1. A.Increase the default test timeout to ten full minutes
  2. B.Use tester.pump(duration), since the animation never settles
  3. C.Run the same widget test in release mode instead
  4. D.Call setState inside the test body to stop the frames
Show answer

Answer: B. Use tester.pump(duration), since the animation never settles

pumpAndSettle keeps pumping frames until no more are scheduled. An indeterminate progress indicator schedules frames forever, so it never settles and the call times out. Pump a fixed duration instead, or replace the loading state with a fake that has finished.

43. List<dynamic> is not a List<String>

Decoding `{"tags": ["a", "b"]}` and writing `List<String> tags = json['tags'];` throws a type error at runtime. What fixes it?

  1. A.Build a typed list with List<String>.from(json['tags'])
  2. B.Declare the variable as final instead of using a type
  3. C.Call jsonDecode twice on the same input string
  4. D.Wrap the assignment in a try block and ignore it
Show answer

Answer: A. Build a typed list with List<String>.from(json['tags'])

jsonDecode builds a List<dynamic>, and Dart generics are reified, so a List<dynamic> is not a List<String> even if every element is a string. Creating a new typed list with List<String>.from or a lazy view with cast<String>() gives the right type. Code generators such as json_serializable handle this for you.

44. Flutter's layout rule

Which sentence correctly describes Flutter's layout protocol?

  1. A.Sizes go down, constraints go up, and the child sets its position
  2. B.Each widget picks any size and the screen scrolls to fit
  3. C.Constraints go down, sizes go up, and the parent sets the position
  4. D.The root widget measures every leaf before any layout
Show answer

Answer: C. Constraints go down, sizes go up, and the parent sets the position

A parent passes min and max width and height to each child. The child picks a size within those limits and reports it back, and the parent then decides where to place it. A child cannot be bigger than its constraints allow, which explains many surprising layouts.

45. Container ignores its width

Why does this Container fill the whole screen instead of being 100 × 100?

void main() => runApp(
  Container(width: 100, height: 100, color: Colors.red),
);
  1. A.Container ignores width and height unless a color is set
  2. B.MaterialApp scales every child up to the screen size
  3. C.The width is in centimetres, not logical pixels
  4. D.The screen gives tight constraints, forcing the child to be full size
Show answer

Answer: D. The screen gives tight constraints, forcing the child to be full size

The root view passes tight constraints equal to the screen size, so its child must be exactly that size and width: 100 is ignored. Wrapping the Container in Center or Align loosens the constraints, and then 100 × 100 is honoured.

46. Blocking back with unsaved changes

On Android 14 and later, predictive back gestures need to know in advance whether a route may pop. Which Flutter widget handles an "unsaved changes" guard correctly?

  1. A.WillPopScope returning a Future from onWillPop
  2. B.PopScope with canPop set from the form state
  3. C.GestureDetector listening for a left swipe
  4. D.A WillPopScope inside a SafeArea widget
Show answer

Answer: B. PopScope with canPop set from the form state

Predictive back shows a preview of the previous screen before the gesture completes, so the system must know ahead of time whether popping is allowed. PopScope declares this with canPop and reports attempts through onPopInvokedWithResult, where you can show a dialog. WillPopScope is deprecated because its async callback cannot support this.

47. Turning a callback API into a Future

An old SDK reports results through onSuccess and onError callbacks. What does this Dart code use to expose it as a Future?

Future<String> scan() {
  final c = Completer<String>();
  sdk.scan(onSuccess: c.complete, onError: c.completeError);
  return c.future;
}
  1. A.A StreamController that is never closed
  2. B.A Timer that polls the SDK every second
  3. C.An Isolate that blocks until a result arrives
  4. D.A Completer, completed from the callbacks
Show answer

Answer: D. A Completer, completed from the callbacks

A Completer creates a Future you can finish later with complete or completeError. Wrapping callback-style APIs this way lets callers use await and try/catch. Make sure every path completes exactly once, or callers will hang or hit a "Future already completed" error.

Ready to test yourself?

Take a 15-question Flutter MCQ test with a score at the end, or practise the full Flutter question bank and earn points on the leaderboard.