Skip to content

PUBLIC QUESTION PREVIEW

Flutter & Dart interview questions

Widgets, state management (Riverpod, Bloc), navigation, async, animations, platform channels, and testing.

Showing 12 of 50 source questions. Sample answers are study material, not employer-specific hiring guidance.

How to work through this preview

Attempt each question before reading its answer. For a concept, give a definition and a concrete example. For code, state constraints, walk through a small input, and check complexity. For design, separate requirements from assumptions and explain failure handling. Use real situations for behavioral answers.

QUESTION 1 / easy / conceptual

What is Flutter? How does it differ from React Native?

Sample answer

Flutter: Google's open-source UI toolkit for building natively compiled applications for mobile (Android/iOS), web, desktop, and embedded from a single codebase using Dart. Key differentiator — rendering approach: - Flutter: draws its own UI using its own rendering engine (Skia, now Impeller). No native widgets — every pixel is painted by Flutter itself. - React Native: uses a JavaScript bridge to call native components (UIButton, TextView). UI = real native platform widgets. Comparison: | Aspect | Flutter | React Native | | Language | Dart | JavaScript/TypeScript | | UI rendering | Own engine (Skia/Impeller) | Platform native widgets | | Performance | Near-native (no bridge overhead) | Good but bridge adds latency | | Look & feel | Pixel-perfect, consistent across platforms | Matches platform native look | | Ecosystem | Growing (pub.dev) | Mature (npm) | | Hot reload | Yes (Stateful hot reload) | Yes (Fast Refresh) | Flutter advantages: - Pixel-perfect custom designs consistent across platforms - No bridge = better animation performance - One codebase for mobile + web + desktop + embedded - Strong Google backing; used by Google Pay, Alibaba (Xianyu) React Native advantages: - JavaScript/TypeScript — huge developer pool - Access to native components (feels more at home on each platform) - Mature ecosystem and community Flutter is popular in India: Zepto, Nykaa, CRED all use Flutter for mobile apps.

Hints to guide your next attempt

  • Skia/Impeller rendering engine, not native components
  • Dart vs JavaScript

Source tags: flutter / react-native / dart / cross-platform / mobile

QUESTION 2 / easy / conceptual

What is a Widget in Flutter? Explain StatelessWidget vs StatefulWidget.

Sample answer

Widget: the fundamental building block in Flutter. Everything you see — buttons, text, layouts, animations, even padding — is a widget. The UI is a tree of widgets. "Everything is a Widget" philosophy: - Text, Icon, Container, Row, Column → visible elements - Padding, Align, Center, SizedBox → layout helpers - GestureDetector, InkWell → interaction - Theme, MediaQuery → inherited data - Even the app root (MaterialApp, CupertinoApp) is a widget StatelessWidget: - Immutable: built once from its configuration (constructor params), never rebuilds internally - No state that changes over time - Use when: displaying data that doesn't change (label, icon, static card) class GreetingCard extends StatelessWidget { final String name; const GreetingCard({required this.name}); @override Widget build(BuildContext context) => Text('Hello, $name'); } StatefulWidget: - Has mutable internal state that can change over time - Two classes: the widget itself (immutable config) + State object (mutable) - Rebuild triggered by setState(() { ... }) - Use when: checkbox, counter, form input, animated element class Counter extends StatefulWidget { @override State<Counter> createState() => _CounterState(); } class _CounterState extends State<Counter> { int count = 0; @override Widget build(BuildContext context) { return ElevatedButton( onPressed: () => setState(() => count++), child: Text('Count: $count'), ); } } Rule of thumb: default to StatelessWidget; add Stateful only when the widget needs to remember and update its own data.

Hints to guide your next attempt

  • Everything is a widget
  • Stateless = immutable, Stateful = mutable state

Source tags: widget / stateless / stateful / flutter / dart

QUESTION 3 / medium / conceptual

What is the Flutter widget tree? Explain the three trees.

Sample answer

Flutter maintains three parallel trees for rendering: 1. Widget Tree - Immutable blueprint; describes what to render - Rebuilt frequently (every setState, every animation frame) - Lightweight — just configuration objects - You write this in your code 2. Element Tree - Mutable, long-lived objects that correspond to each widget - Maintains the link between widget config and render objects - Flutter's reconciliation happens here: when widgets rebuild, Flutter checks if the element can be reused (same type at same position) or must be replaced - Similar in concept to React's Fiber tree 3. RenderObject Tree - Handles layout and painting - Most expensive to create/update - Computes sizes, positions, composites layers, paints to canvas - Not rebuilt every frame — only when layout/paint is invalidated Why three trees? - Separation of concerns: widget (config) → element (lifecycle) → render (draw) - Performance: rebuilding widgets is cheap (immutable objects); reusing elements and render objects is expensive but happens rarely - Flutter's reconciliation algorithm walks the element tree, comparing new widgets to existing ones, reusing render objects where possible (keyed updates) Keys: - Help Flutter identify which element corresponds to which widget when the order changes - Use GlobalKey for element identity across rebuilds; LocalKey (ValueKey, ObjectKey) for list items

Hints to guide your next attempt

  • Widget tree, Element tree, RenderObject tree
  • Each has a different role

Source tags: widget-tree / element-tree / render-object / flutter-internals / reconciliation

QUESTION 4 / easy / conceptual

What is hot reload and hot restart in Flutter? What is the difference?

Sample answer

Both are developer productivity features for seeing code changes immediately without a full rebuild: Hot Reload: - Injects new widget code into the running Dart VM - Preserves the current app state (scroll position, counter value, navigation stack) - Rebuilds the widget tree from the root - Takes < 1 second - Limitation: doesn't apply changes to: initState(), main(), global initializers, or static fields - Use for: UI tweaks, styling, layout changes Hot Restart: - Fully restarts the Dart VM and app from scratch - State is lost (back to initial state) - Recompiles the entire app but is still faster than a full rebuild (~2-5 seconds) - Use for: changes to initState(), new dependencies, main() changes, global variable changes Full Rebuild (Stop + Run): - Rebuilds everything from scratch including native code changes - Required for: adding new packages (pubspec.yaml changes), modifying native code (Android/iOS), modifying AndroidManifest / Info.plist Keyboard shortcuts (VS Code / IntelliJ): - Hot Reload: r (lowercase) in terminal, or Cmd+S / save file - Hot Restart: R (uppercase) in terminal The hot reload feature is one of Flutter's most praised developer experience features — makes iterating on UI extremely fast. React Native has a similar feature (Fast Refresh).

Hints to guide your next attempt

  • Hot reload preserves state, hot restart resets it

Source tags: hot-reload / hot-restart / flutter-dev / developer-experience

QUESTION 5 / medium / conceptual

What is the BuildContext in Flutter? Why is it important?

Sample answer

BuildContext: a handle to the location of a widget in the widget tree. It knows where in the tree a widget sits and gives access to inherited data flowing down from ancestors. Every widget's build() method receives a BuildContext: Widget build(BuildContext context) { ... } What you can do with context: 1. Access inherited widgets and theme: Theme.of(context).colorScheme.primary MediaQuery.of(context).size.width Localizations.of(context, AppLocalizations) 2. Navigate: Navigator.of(context).push(...) Navigator.of(context).pop() 3. Access Provider data (state management): final user = context.watch<UserModel>(); final user = context.read<UserModel>(); 4. Show overlays: ScaffoldMessenger.of(context).showSnackBar(...) showDialog(context: context, builder: ...) Common mistake: using BuildContext after an async gap // WRONG — context may be invalid after await Future<void> doSomething() async { await someAsyncCall(); Navigator.of(context).pop(); // context may be unmounted } // CORRECT — check if still mounted Future<void> doSomething() async { await someAsyncCall(); if (!mounted) return; Navigator.of(context).pop(); Why it matters: - Context is specific to a widget's position in the tree — the same Theme.of(context) call inside different widgets may return different themes if there are nested Theme overrides - If you pass context from a parent to a child function, that function inherits the parent's tree position, not the child's

Hints to guide your next attempt

  • Handle to location in widget tree
  • Used for Theme, Navigator, MediaQuery, Provider

Source tags: buildcontext / flutter / inherited-widget / theme / navigator

QUESTION 6 / easy / conceptual

What are the most common layout widgets in Flutter? Explain Row, Column, Stack, and Expanded.

Sample answer

Flutter layout is built from composable layout widgets: Row: - Arranges children HORIZONTALLY - mainAxisAlignment: controls spacing along horizontal axis - crossAxisAlignment: controls vertical alignment of children Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Icon(Icons.star), Text('4.5')], ) Column: - Arranges children VERTICALLY - Same mainAxis/crossAxis properties (but mainAxis is vertical) Column( crossAxisAlignment: CrossAxisAlignment.start, children: [Text('Title'), Text('Subtitle')], ) Stack: - Overlaps children on top of each other (like CSS position: absolute) - Children are positioned using Positioned() or default to top-left Stack( children: [ Image.network(url), Positioned(bottom: 8, right: 8, child: Icon(Icons.favorite)), ], ) Expanded: - Inside Row/Column: makes a child fill the available space along the main axis - flex: controls the proportion (like CSS flex-grow) Row( children: [ Expanded(flex: 2, child: Text('Left')), Expanded(flex: 1, child: Text('Right')), ], ) Other key layout widgets: - Container: box with padding, margin, decoration, size constraints - SizedBox: fixed size spacer or box - Padding: adds padding around a child - Center: centers child in available space - Flexible: like Expanded but allows child to be smaller than allotted space - Wrap: like Row/Column but wraps to next line when space runs out

Hints to guide your next attempt

  • Row/Column for linear, Stack for overlapping, Expanded to fill available space

Source tags: layout / row / column / stack / expanded / flutter-widgets

QUESTION 7 / medium / conceptual

What is state management in Flutter? Compare Provider, Riverpod, and Bloc.

Sample answer

State management: the pattern for managing app state (data that changes over time) and making it accessible across the widget tree without prop-drilling. Why needed: for small widgets, setState() is fine. For shared state across many widgets (user session, cart, theme), you need a solution. 1. Provider (simple, official Flutter recommendation) - InheritedWidget wrapper; ChangeNotifier + Consumer - Simple, lightweight, good for small-medium apps - ChangeNotifier notifies listeners on notifyListeners() class CartModel extends ChangeNotifier { List<Item> items = []; void add(Item item) { items.add(item); notifyListeners(); } } // Usage: context.watch<CartModel>().items context.read<CartModel>().add(item) 2. Riverpod (Provider's evolved successor, by same author) - Compile-time safe (no runtime ProviderNotFoundException) - Works outside widget tree (testable without BuildContext) - Supports async providers (FutureProvider, StreamProvider) natively - More boilerplate but much more powerful final cartProvider = StateNotifierProvider<CartNotifier, List<Item>>((ref) => CartNotifier()); // Usage: ref.watch(cartProvider) ref.read(cartProvider.notifier).add(item) 3. Bloc / Cubit (BLoC pattern — Business Logic Component) - Strict unidirectional data flow: Events → Bloc → States - Cubit: simpler version without events; just emit new states - Best for: complex apps, large teams, testability, strict architecture - More boilerplate class CounterCubit extends Cubit<int> { CounterCubit() : super(0); void increment() => emit(state + 1); } When to use what: - Small app or learning: setState + Provider - Medium app: Riverpod (easier than Bloc, more robust than Provider) - Large team / complex app: Bloc (strict, testable, well-documented)

Hints to guide your next attempt

  • As app grows, passing state down widget tree becomes unwieldy
  • Each approach has different trade-offs

Source tags: state-management / provider / riverpod / bloc / flutter

QUESTION 8 / medium / conceptual

What is async/await in Dart? How do Future and Stream differ?

Sample answer

Dart has first-class async support based on Futures and Streams. Future<T>: represents a single asynchronous value that will be available at some point. - Like a Promise in JavaScript - States: uncompleted → completed with value OR completed with error Future<User> fetchUser(String id) async { final response = await http.get(Uri.parse('/users/$id')); return User.fromJson(jsonDecode(response.body)); } // Usage: final user = await fetchUser('123'); // or with then: fetchUser('123').then((user) => print(user.name)).catchError((e) => print(e)); async/await: syntactic sugar over Future. An async function returns a Future implicitly. await suspends execution until the Future completes. Stream<T>: a sequence of asynchronous events over time. - Like an Observable / AsyncGenerator - Use for: real-time data (WebSocket messages, file download progress, sensor data, Firestore snapshots) Stream<int> countDown(int from) async* { for (int i = from; i >= 0; i--) { yield i; await Future.delayed(Duration(seconds: 1)); } } // Consuming: await for (final count in countDown(5)) { print(count); } // or: countDown(5).listen((count) => print(count)); StreamController: create custom streams StreamController<String> controller = StreamController(); controller.sink.add('hello'); controller.stream.listen((msg) => print(msg)); controller.close(); // always close when done Future vs Stream: - Future: one value, one time (HTTP request response) - Stream: many values, over time (WebSocket, Firestore realtime, user location) In Flutter: FutureBuilder and StreamBuilder widgets rebuild UI when data arrives.

Hints to guide your next attempt

  • Future = single async value, Stream = sequence of async values

Source tags: dart / future / stream / async-await / asynchronous

QUESTION 9 / medium / conceptual

What is FutureBuilder and StreamBuilder in Flutter?

Sample answer

FutureBuilder and StreamBuilder: Flutter widgets that rebuild their UI in response to async data from a Future or Stream, handling loading, error, and data states declaratively. FutureBuilder<T>: FutureBuilder<List<User>>( future: fetchUsers(), // Future<List<User>> builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return CircularProgressIndicator(); } if (snapshot.hasError) { return Text('Error: ${snapshot.error}'); } if (!snapshot.hasData || snapshot.data!.isEmpty) { return Text('No users found'); } return ListView.builder( itemCount: snapshot.data!.length, itemBuilder: (ctx, i) => Text(snapshot.data![i].name), ); }, ) ConnectionState values: - none: not connected - waiting: async op is running - active: stream has emitted at least once (streams only) - done: future completed or stream closed StreamBuilder<T>: - Same structure but reacts to every new Stream event StreamBuilder<List<Message>>( stream: chatStream, // Stream<List<Message>> builder: (context, snapshot) { if (!snapshot.hasData) return CircularProgressIndicator(); return MessageList(messages: snapshot.data!); }, ) Best practices: - Store the Future/Stream in a variable (in initState or State field) — NOT inline in build(). Inline creates a new Future every rebuild: // WRONG: fetchUsers() called on every rebuild // RIGHT: _future = fetchUsers() in initState, pass _future to FutureBuilder - For complex async state, prefer Riverpod FutureProvider/StreamProvider or Bloc — more testable and composable

Hints to guide your next attempt

  • Widgets that rebuild when async data arrives
  • ConnectionState, snapshot.data, snapshot.error

Source tags: futurebuilder / streambuilder / flutter / async / widget

QUESTION 10 / medium / conceptual

What is Navigator in Flutter? Explain Navigator 1.0 vs Navigator 2.0.

Sample answer

Flutter Navigator manages a stack of Route objects — each route is a full-screen page. Navigator 1.0 (Imperative): // Push a new route Navigator.of(context).push( MaterialPageRoute(builder: (ctx) => DetailPage(id: 42)), ); // Push named route Navigator.of(context).pushNamed('/detail', arguments: {'id': 42}); // Pop current route Navigator.of(context).pop(); // Replace current route Navigator.of(context).pushReplacement(MaterialPageRoute(...)); // Pop until a named route Navigator.of(context).popUntil(ModalRoute.withName('/home')); Define named routes in MaterialApp: MaterialApp( initialRoute: '/', routes: { '/': (ctx) => HomePage(), '/detail': (ctx) => DetailPage(), }, ) Navigator 2.0 (Declarative — Flutter 1.22+): - Exposes a Router widget driven by RouterDelegate and RouteInformationParser - App state determines which pages are on the stack (not imperative push/pop) - Designed for deep linking, web URL sync, back button handling - More complex to set up; addresses Navigator 1.0 limitations on web Navigator 2.0 is typically used via packages: - go_router (official, recommended by Flutter team): declarative routing with URL patterns - auto_route: code generation-based routing go_router example: final router = GoRouter(routes: [ GoRoute(path: '/', builder: (ctx, state) => HomePage()), GoRoute(path: '/detail/:id', builder: (ctx, state) => DetailPage(id: state.pathParameters['id']!)), ]); When to use which: - Navigator 1.0: simple mobile apps, no deep linking required - go_router / Navigator 2.0: web apps, deep linking, URL-based navigation, complex routing

Hints to guide your next attempt

  • Stack of routes
  • Navigator 2.0 is declarative; 1.0 is imperative

Source tags: navigator / routing / flutter / go-router / navigation

QUESTION 11 / medium / conceptual

How does Flutter handle animations? Explain AnimationController and Tween.

Sample answer

Flutter animations are built from composable primitives: AnimationController: - Drives the animation timeline from 0.0 to 1.0 (or custom range) over a duration - Requires a TickerProvider (use SingleTickerProviderStateMixin) - Methods: forward(), reverse(), repeat(), stop() Tween<T>: - Maps the 0.0-1.0 controller value to a typed range (e.g., double, Color, Offset) - animate() connects the Tween to the controller AnimationBuilder: - Rebuilds only itself (not the whole widget tree) when animation value changes Full example — fade in: class FadeInWidget extends StatefulWidget { ... } class _FadeInWidgetState extends State<FadeInWidget> with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation<double> _animation; @override void initState() { super.initState(); _controller = AnimationController(duration: Duration(milliseconds: 500), vsync: this); _animation = Tween<double>(begin: 0.0, end: 1.0).animate(_controller); _controller.forward(); // start immediately } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) => FadeTransition(opacity: _animation, child: child); } Implicit vs explicit animations: - Explicit: AnimationController + Tween + AnimatedBuilder — full control - Implicit: AnimatedContainer, AnimatedOpacity, AnimatedAlign — Flutter manages the controller for you // Implicit animation — just change the value, Flutter animates automatically: AnimatedOpacity( opacity: _isVisible ? 1.0 : 0.0, duration: Duration(milliseconds: 300), child: Text('Hello'), ) Hero animations: Hero(tag: 'product-image-42', child: Image.network(url)) // Wrap the same tag on the destination page → Flutter animates the shared element between screens

Hints to guide your next attempt

  • AnimationController drives the clock, Tween maps values, AnimatedBuilder rebuilds

Source tags: animations / animation-controller / tween / flutter / implicit-animation

QUESTION 12 / medium / conceptual

How do you make HTTP requests in Flutter? Walk through the http and dio packages.

Sample answer

Flutter doesn't have a built-in HTTP client; use packages from pub.dev. http package (simple): import 'package:http/http.dart' as http; import 'dart:convert'; Future<List<Post>> fetchPosts() async { final response = await http.get( Uri.parse('https://api.example.com/posts'), headers: {'Authorization': 'Bearer $token'}, ); if (response.statusCode == 200) { final List<dynamic> data = jsonDecode(response.body); return data.map((j) => Post.fromJson(j)).toList(); } else { throw Exception('Failed to load posts: ${response.statusCode}'); } } POST: final response = await http.post( Uri.parse('/api/posts'), headers: {'Content-Type': 'application/json'}, body: jsonEncode({'title': 'New Post', 'content': 'Hello'}), ); Dio package (feature-rich): - Interceptors (add auth headers to every request automatically) - Request cancellation - Timeout configuration - File download/upload with progress - FormData support final dio = Dio(BaseOptions( baseUrl: 'https://api.example.com', connectTimeout: Duration(seconds: 5), receiveTimeout: Duration(seconds: 3), )); // Add auth interceptor dio.interceptors.add(InterceptorsWrapper( onRequest: (options, handler) { options.headers['Authorization'] = 'Bearer $token'; handler.next(options); }, )); // GET final response = await dio.get('/posts'); List<Post> posts = (response.data as List).map((j) => Post.fromJson(j)).toList(); // POST await dio.post('/posts', data: {'title': 'New', 'content': 'Hello'}); When to use which: - http: simple, lightweight, no interceptors needed - dio: auth token refresh, file upload, timeout config, retry logic Always handle errors and show proper UI states (loading, error, empty, data).

Hints to guide your next attempt

  • http is simple, dio has interceptors and more features
  • Always decode response body

Source tags: http / dio / networking / flutter / api

Check understanding, not recognition

  • Can you explain the answer without reading it?
  • Can you show when the approach fails or needs a different assumption?
  • Can you connect the concept to a real project, task, or decision you have made?
  • Can you distinguish a simplified interview example from a production requirement?

A LITTLE MORE CLARITY

Frequently asked questions

How many Flutter & Dart questions are shown here?

This public preview shows 12 questions with the supplied answers from the app's 50-question Flutter & Dart bank. Full interactive practice requires signing in.

Should I memorize the sample answers?

Use them as reference explanations, not a script or a guarantee of technical correctness for every environment. Explain your assumptions, validate code against your language and version, and discuss trade-offs. Behavioral answers should be built from your own experience.

What do hints and solution steps mean?

Hints identify ideas to consider before reading the answer. When the source question includes steps, they are shown as a separate walkthrough. Example capacities and design targets in a solution are assumptions for that exercise, not real system statistics.

BUILD YOUR NEXT OPPORTUNITY

Practice Flutter & Dart actively.

Sign in to use the full topic bank and interactive practice workspace.

Open Topic Practice