Mobile Apps

Why Your Flutter App Janks on Older Android Phones

The app is silk on your test device and a slideshow on your customer’s three-year-old Android. That gap isn’t Flutter being slow: Flutter renders at 60fps on remarkably weak hardware when the code lets it. Flutter app jank on older phones is almost always the app doing avoidable work on the one thread that can’t afford it.

Fast phones forgive wasteful code. Old phones invoice you for every frame, and your users hold the old phones.

Illustration of a mobile screen with a simple, tap-friendly interface, Why Your Flutter App Janks on Older Android Phones
What causes Flutter app jank on budget Android phones, from needless rebuilds to heavy lists and images, and how to profile and fix each…

Rebuilds you didn’t mean to trigger

The most common cause: giant widgets rebuilt wholesale on every small state change. A setState high in the tree rebuilds every child below it, sixty times a second during animation. On a flagship the waste is invisible; on a budget chip it’s dropped frames.

The fixes are structural. Push state down so rebuilds touch the smallest possible subtree, split monolithic build methods into focused widgets, and use const constructors everywhere the compiler allows, because const widgets skip rebuilds entirely. Selective listening (select in Provider/Riverpod, granular builders) stops your UI from redrawing because an unrelated field changed.

Lists built the expensive way

A scrolling list built with a plain Column or a ListView without the .builder constructor lays out every item up front: hundreds of widgets for the twelve on screen. Older devices pay that bill in startup stutter and scroll jank. ListView.builder and friends build only what’s visible; fixed itemExtent where item heights are uniform makes scroll math nearly free. This one refactor fixes more budget-phone jank than any other single change.

Images doing GPU work per frame

Full-resolution photos decoded into small thumbnails burn memory and decode time old phones don’t have. Give Flutter the target size with cacheWidth/cacheHeight so decoding happens once at the right resolution.

And treat certain "free" effects as luxury items: Opacity wrapping complex subtrees, BackdropFilter blurs, and shadows not isolated in a RepaintBoundary force extra render work that flagship GPUs shrug off and budget GPUs visibly can’t.

Animations that rebuild more than they move

A common source of jank is an animation driven by setState in a large widget. Every tick rebuilds the whole screen just to move one element. Use AnimatedBuilder and pass the parts that never change as its child, so only the moving piece rebuilds each frame.

The same logic applies to fades. Animating an Opacity widget is costly, while FadeTransition or AnimatedOpacity are built for the job. Avoid animating clips and blurs where a simpler effect would do.

Infographic summarising “Why Your Flutter App Janks on Older Android Phones”: Rebuilds you didn’t mean to trigger; Lists built the expensive way; Images doing GPU work per frame; Animations that rebuild more than they move; Heavy work on the UI thread; How to find Flutter app jank in DevTools…
The article at a glance.

Heavy work on the UI thread

JSON parsing a large response, image processing, database queries in a build path: anything over a few milliseconds on the main isolate steals frames. Move real computation to a background isolate with compute(), and keep build methods pure layout.

How to find Flutter app jank in DevTools

Guessing wastes time, because jank usually has one or two real sources. Profiling tells you which kind of problem you have before you start rewriting.

  1. Run the app with flutter run --profile on the slowest phone you can find.
  2. Open DevTools and go to the Performance view, then use the screen that feels janky.
  3. Look at which thread is over budget. Slow UI thread frames point at build, layout and Dart work. Slow raster thread frames point at expensive painting, such as opacity, clips and blurs.
  4. Turn on rebuild tracking to see which widgets rebuild far more often than they should.
  5. Fix the worst offender, then measure again before touching anything else.

Flutter’s guide to profiling UI performance explains how to read those two threads in more detail.

Profile on the hardware that matters, in profile mode

Two testing mistakes create false confidence: profiling on your own fast phone, and judging performance in debug mode (debug Flutter is dramatically slower by design). Test in profile mode on a genuinely low-end device, the sub-$150 Android your actual users hold.

Flutter’s DevTools timeline shows exactly which frames blew the 16ms budget and which widgets were rebuilding when they did; the official performance best practices cover the full toolkit.

Older phones are also short on storage and often sit on slower connections, so app weight matters as much as frame time. I cover that side in reducing Flutter app size before you hit the store limit. The principle carries over to the web too: if you also run a WordPress site, how to speed up a WordPress site applies the same measure-first, fix-second approach.

Performance is one of several basics

Jank is the problem users feel first, but it is rarely the only shortcut a deadline creates. Apps that talk to a backend should get the same scrutiny on the server side, and the authentication mistakes found in small SaaS apps are the ones I check next.

Budget-phone performance is a discipline, not a patch. It’s why I keep an aging test device in the drawer for every Flutter build I ship. The app store rating doesn’t come from how the app runs on the developer’s phone; it comes from how it runs on everyone else’s.

Questions people ask

What causes jank in a Flutter app?

Jank happens when a frame takes longer than its budget to build or paint. Common causes are large widgets rebuilding on every state change, long lists built all at once, oversized images, costly effects such as opacity and blur, and heavy work like JSON parsing running on the main isolate.

Why is my Flutter app smooth on my phone but slow on others?

Fast phones hide wasteful code. A flagship processor and GPU can absorb unnecessary rebuilds and expensive effects, while a budget Android device cannot. Debug mode also makes Flutter much slower, so always judge performance in profile mode on a genuinely low-end device.

How do I profile a Flutter app for performance?

Run the app with flutter run --profile on a slow device, open DevTools and use the Performance view while reproducing the jank. Check whether the UI thread or the raster thread is over budget, turn on rebuild tracking, and fix the worst offender before measuring again.

Does ListView.builder improve Flutter performance?

Yes, for long or growing lists. A plain Column or a default ListView lays out every item up front, while ListView.builder only builds the items on screen. Setting a fixed itemExtent when all items share a height makes scrolling cheaper still.

Comments

Leave a comment

0 / 3000
Comments are moderated. Links are not clickable and your email is never published. See the privacy policy.
keep reading

Related articles

Usually replies within a day
let’s talk

Tell me what you want to build

A website, an app, some automation, or something you’re still figuring out. Tell me the problem and I’ll give you a straight answer on what it takes. No pressure, no sales team.