Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For a long Flutter list, begin with ListView.builder so rows are created as they are needed. Add stable keys when items can move and their state should stay with the same data item. Keep expensive work out of frequently called build() methods, narrow state changes to the widgets that need them, and supply accurate row-extent hints when possible. To find actual jank, profile the app in profile mode rather than judging debug-mode timing.

Choose lazy construction for long lists

The ordinary ListView constructor takes a concrete collection of children, creating them up front. ListView.builder instead creates children as they scroll into view, which suits large, long, or unbounded data sets. Flutter describes this distinction in its long-lists guide.

A typical builder uses the data source’s length for itemCount and returns the corresponding row from itemBuilder:

ListView.builder(
  itemCount: items.length,
  itemBuilder: (context, index) {
    final item = items[index];
    return ListTile(title: Text(item.title));
  },
)

Providing itemCount when the data length is known lets the list represent its bounds. Flutter’s cookbook uses 10,000 generated strings as an illustrative input; that is an example, not a benchmark or a recommended threshold. For a small, fixed group of children, a regular ListView can be simpler.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use keys to preserve item identity when lists change

Without keys, Flutter generally matches widgets by runtime type and position. When children are inserted, removed, or reordered, a row’s local state can therefore remain associated with a position rather than the logical data item. Flutter’s UI documentation explains how keys help matching entries retain state with their semantic item.

When row-local state should follow an item, give each row a key derived from a stable, unique identifier in the underlying data—not its current index. Keys must be unique among siblings. A key expresses identity; it is not a universal performance switch, and adding keys to a static list does not by itself guarantee faster rendering.

Reduce avoidable rebuild work

Flutter may call build() frequently, including when an ancestor rebuilds. Keep repeated or expensive computation out of that method, and organize the UI around the parts of state that actually change.

  • Split a large widget into smaller widget classes along state boundaries.
  • Call setState() as close as practical to the subtree that needs updating, rather than rebuilding a broad ancestor for a local change.
  • Prefer reusable widget classes over helper functions for UI pieces.
  • Use const constructors when inputs are compile-time constants; this can let Flutter short-circuit some rebuild work.

These practices reduce avoidable work; they do not eliminate rebuilds when a widget’s inputs have changed. Flutter’s performance best-practices guide covers keeping build methods efficient and structuring widgets effectively.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Provide row extents when you can describe them accurately

Scrolling code may need to determine child dimensions. Supplying an accurate extent model can avoid some of that work, especially when scroll position changes substantially. Flutter’s long-lists guide describes three options:

Option Use it when Important condition
itemExtent Every row has the same known extent. The fixed extent must match the rendered rows.
prototypeItem A representative row can express the common fixed extent. The prototype must reflect the dimensions the list should use.
itemExtentBuilder Rows vary in extent, but their dimensions can be provided by index. The callback must accurately represent each rendered extent.

If row dimensions are not fixed or reliably known, do not force a sizing model that conflicts with the content.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Diagnose jank in profile mode

Debug-mode timing is not a reliable measure of release performance. Flutter states that its default debug build is “not indicative of release performance” in the rendering performance guide. Use profile mode on a representative target when assessing frame performance.

  1. Reproduce the slow scroll or other problem on the device and workload that matter.
  2. Run a profile-mode build, then inspect the Performance View or Performance Overlay to identify costly frames.
  3. Use rebuild profiling to check which widgets rebuild and whether the pattern points to avoidable work.
  4. Change one suspected bottleneck at a time, then compare measurements under the same conditions.

Flutter’s Performance View documentation describes the tooling. Results depend on the app, Flutter version, device, and workload; framework guidance does not establish a universal list-size cutoff or a guaranteed speedup.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.