All topics

QUESTIONS AND ANSWERS

Flutter

What is Flutter, and what problem does it solve?

Flutter is a multiplatform UI toolkit built with Dart. It lets teams share much of their code across mobile, web, and desktop while still integrating with the host operating system. Supported platforms and capabilities depend on the stable SDK version; see the architectural overview and supported platform matrix.

What is the difference between a Widget, an Element, and a RenderObject?

A Widget is an immutable configuration that describes part of the UI. An Element represents its mounted instance and position in the tree, coordinates updates, and can retain state; RenderObjects handle layout and painting. This separation lets Flutter recreate Widget objects without necessarily rebuilding the entire UI; see the Flutter architectural overview.

When should you use StatelessWidget or StatefulWidget?

Use StatelessWidget when its output depends only on the configuration it receives and inherited state; use StatefulWidget when part of the UI must retain local mutable state across rebuilds. The Widget remains immutable: a separate State object holds the state and notifies Flutter of changes, usually through setState. See the guide to stateful widgets.

What is the lifecycle of a State object?

The framework creates State, calls initState once, may call didChangeDependencies and didUpdateWidget when dependencies or configuration change, and runs build whenever it needs to describe the UI. In dispose, cancel subscriptions, controllers, and timers; after dispose, do not update that state. The UI and lifecycle guide describes these callbacks.

Why should build be fast and free of side effects?

build can run many times, more often than a developer might expect; its job is to return a UI description for the current state. Avoid starting requests, changing state, or doing expensive computation there: trigger effects from an appropriate action or lifecycle event and prepare data outside build. See the architectural overview and performance best practices.

What are Keys for, and when should you avoid GlobalKey?

Keys help the framework identify which logical Element corresponds to each Widget as the tree changes; in dynamic lists, a stable ValueKey prevents row state from being associated with the wrong item. GlobalKey identifies an Element across the app and can reparent subtrees or access State, but it has a cost and should be long-lived rather than recreated in every build. See Keys and lifecycle and the GlobalKey API reference.

How does Flutter layout work?

A parent gives its child constraints; the child chooses a size within them; and the parent positions it. So, when a layout overflows or has an unexpected size, first inspect the constraints each Widget receives instead of adding arbitrary dimensions. The rule and examples are in Understanding constraints.

What does BuildContext represent, and what care is needed after await?

BuildContext represents a Widget's location in the tree, allowing it to look up inherited dependencies, theme, navigation, or localization. Do not use it after an asynchronous gap if the Widget may have been unmounted; check that it is still mounted before navigating or showing UI. See the BuildContext API and its mounted property.

How do you make a Flutter UI adaptive?

Design for the available space and input style, not just the device model. MediaQuery or LayoutBuilder can measure the app's current area; then you can change layout, navigation, or controls for narrow windows, tablets, foldables, keyboards, and mice. See the guide to adaptive and responsive design.

Where should state live: inside a Widget or shared across the app?

Ephemeral state, such as whether a field is expanded, can live in the closest Widget that uses it. State shared across screens should have a single source of truth and be exposed as observable data; the UI sends events and presents the resulting state. The guide distinguishes ephemeral state from app state.

Which responsibilities does the recommended architecture separate?

Flutter recommends separating UI and data: a view renders state and forwards actions; a ViewModel transforms data into screen state; a repository acts as the source of truth and centralizes caching, errors, retries, and synchronization; a service encapsulates an external source such as HTTP, files, or a native API. These are adaptable recommendations, not a mandatory architecture; see the app architecture guide.

When should you add a domain layer, and how should you inject dependencies?

Add use cases when a business operation is complex or reused by multiple ViewModels; an extra class for every simple operation adds abstractions without value. Pass dependencies through constructors so services and repositories can be replaced in tests, and introduce a DI container when it helps manage the dependency graph. See the architecture recommendations and communication between layers.

What is the difference between a Future and a Stream?

A Future represents an asynchronous operation that completes with one value or an error; a Stream represents a sequence of events over time. The UI should model loading, success, empty, and error states explicitly, stop listening when it no longer needs the source, and prevent stale responses from overwriting newer data. Services and repositories expose these abstractions according to their data source; see the Flutter architecture guide.

What does concurrency mean in Flutter, and when should you use an isolate?

Dart code runs in isolates with separate memory, which communicate by messages. Asynchronous I/O does not necessarily block the UI; move CPU-heavy computation to an isolate when measurements show jank, and avoid the overhead for small work without evidence. Isolates cannot manipulate Widgets or directly share mutable state; see Concurrency and isolates.

How should an app respond to lifecycle changes?

An app can lose focus, pause, return to the foreground, or detach from its engine; do not assume the process will remain alive so it can save data at the end. Observe changes with AppLifecycleListener or WidgetsBindingObserver and pause or resume resources that actually depend on visibility, such as playback or sensors. Exact states and transitions vary by platform; see the AppLifecycleListener API.

How should you structure an HTTP request and handle failures?

Isolate transport in a service, convert JSON to models that can be validated, and let the repository decide caching, retries, and error policy. Represent loading, data, and error in the UI; do not treat a non-success HTTP response as success just because the connection completed. Flutter documents the HTTP package and network requests and JSON handling.

Which local storage should you choose?

Use key-value preferences for simple settings, SQLite for structured and queryable data, and a remote database when information must sync across users or devices. Do not store tokens or secrets as ordinary preferences: sensitive storage requires protected platform mechanisms and review of the package used. The official guide compares database options.

What does it mean to design a feature as offline-first?

The UI should be able to read local data and remain useful without a network connection; the repository coordinates local and remote storage and defines when to synchronize, how to retry, and how to resolve conflicts. First agree on consistency requirements with the product: some features show cached data, while others require an explicit refresh. See Offline-first support.

When should you use a plugin, a Platform Channel, or FFI?

First check whether a maintained plugin meets the need. Platform Channels exchange asynchronous messages between Dart and platform code; FFI calls native libraries directly, for example C libraries. Decide based on available APIs, per-platform maintenance cost, real-time requirements, and support for target platforms; integration details can change with SDK and tool versions. See platform channels and FFI.

Which accessibility principles should inform visual design?

Use semantics and understandable labels for screen readers, sufficiently large touch targets, readable contrast, and layouts that still work when text is enlarged. Test navigation with TalkBack or VoiceOver, and do not communicate information only through color or unlabeled icons. See Flutter accessibility and accessible UI design and styling.

How can you check accessibility automatically and manually?

Widget tests can validate labels, touch target size, and contrast with the Accessibility Guideline API. Complement them with screen readers and platform inspectors: an automated check alone cannot confirm that reading order and announcements make sense. See Accessibility testing.

What do unit, widget, and integration tests cover?

A unit test checks an isolated function or class; a widget test validates UI and events in Flutter's test environment; an integration test exercises a broader flow on a device or emulator. Keep most fast checks close to the logic and cover critical end-to-end journeys even though those tests run more slowly. See the testing overview.

How do you diagnose jank or slow rendering?

Reproduce the flow on a physical device, use profile mode, and inspect DevTools Performance for late frames, expensive build or paint work, and unnecessary rebuilds. Optimize after measuring rather than because a class merely looks expensive; debug mode and emulators do not reliably represent release behavior. See performance profiling and best practices.

Which tools help investigate a bug, network issue, or memory problem?

Use the DevTools debugger with breakpoints and stack traces to reproduce failures; Inspector for the tree, constraints, and overflow; Network View for requests; and Memory View to look for retention or excessive allocation. Choose the tool based on your hypothesis and capture a reproducible case. The DevTools suite links to Inspector, Network View, and Memory View.

What does it mean to protect a Flutter app from client-side extraction?

Do not include private credentials, server secrets, or privileged keys in the binary: anything distributed to a device can be extracted. HTTPS and backend controls are essential; obfuscation may make code harder to read, but it does not encrypt resources or prevent reverse engineering. See the official warning about Dart obfuscation.

What should you review before creating a production build?

Separate development, testing, and production settings with flavors; review identifiers, endpoints, permissions, signing, and assets for each variant, then test the release artifact on target devices. Keep symbol maps if you obfuscate so you can symbolize failures. The deployment guide and Android flavors guide describe concrete steps, which vary by platform and version.

In an interview, how would you decide whether Flutter fits a product?

Tie the decision to product goals: how much UI and logic can genuinely be shared, the platform-specific experience users expect, native integrations, measured performance, team skills, and the cost of maintaining plugins. A prototype should test the main risks on representative devices; shared code does not remove the need for platform-specific design, testing, and review. See the Flutter architecture overview and platform adaptations.