DEV Community

kanta13jp1
kanta13jp1

Posted on

Flutter Performance Optimization: const, Lazy Loading, and Image Caching

Flutter Performance Optimization: const, Lazy Loading, and Image Caching

Three rules for perceived speed. Always measure with DevTools first.

1. const: Minimize Rebuilds

const constructors tell Flutter to skip rebuilding a widget during tree
reconstruction. It's one of the cheapest performance wins available.

// Bad: rebuilt every time parent rebuilds
class MyPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('Title'),
        Icon(Icons.star),
        TaskList(),
      ],
    );
  }
}

// Good: static widgets are const — rebuild skipped
class MyPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return const Column(
      children: [
        Text('Title'),
        Icon(Icons.star),
        TaskList(),
      ],
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Catch missing const with flutter analyze:

flutter analyze lib/ | grep "const"
# prefer_const_constructors warning flags every missed opportunity
Enter fullscreen mode Exit fullscreen mode

2. Lazy Loading: Speed Up Initial Render

Don't load everything upfront. Build list items and tabs on demand.

// ListView.builder: items created only when visible
ListView.builder(
  itemCount: tasks.length,
  itemBuilder: (context, index) => TaskCard(task: tasks[index]),
)

// AutomaticKeepAliveClientMixin: preserve tab state after switching
class _TaskTabPageState extends State<TaskTabPage>
    with AutomaticKeepAliveClientMixin {
  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return TaskList();
  }
}

// Network images — show progress while loading
Image.network(
  imageUrl,
  loadingBuilder: (context, child, progress) {
    if (progress == null) return child;
    return const CircularProgressIndicator();
  },
)
Enter fullscreen mode Exit fullscreen mode

3. Image Caching: cached_network_image

// pubspec.yaml: cached_network_image: ^3.3.0

CachedNetworkImage(
  imageUrl: 'https://example.com/avatar.jpg',
  placeholder: (context, url) => const CircularProgressIndicator(),
  errorWidget: (context, url, error) => const Icon(Icons.error),
  memCacheWidth: 200,    // resize to display size in memory
  memCacheHeight: 200,
  // disk cache survives app restarts
)
Enter fullscreen mode Exit fullscreen mode

Server-side resize with Supabase Storage transforms:

final optimizedUrl = supabase.storage
    .from('avatars')
    .getPublicUrl('user123.jpg',
        transform: const TransformOptions(width: 200, height: 200));
Enter fullscreen mode Exit fullscreen mode

Profiling with Flutter DevTools

flutter run --profile
# Open http://127.0.0.1:9100 in browser
Enter fullscreen mode Exit fullscreen mode

Key views:

  • Frame chart: frames exceeding 16ms (60 fps threshold)
  • Widget rebuild: red highlights mark excessive rebuilds
  • Memory: a rising-right graph signals a leak

Summary

const          → attach to static widgets; rebuild skipped for free
Lazy loading   → ListView.builder + AutomaticKeepAlive for fast scroll
Image cache    → cached_network_image + Supabase transforms for right-sized images
Measure first  → DevTools Frame chart to find the bottleneck before optimizing
Enter fullscreen mode Exit fullscreen mode

Performance work without measurement is guesswork. Find the slow frame first,
then fix exactly that.

Top comments (0)