Skip to content
flutter on a 2GB android phone: what actually made our app usable
article3 min read343 viewsAug 10, 2026

flutter on a 2GB android phone: what actually made our app usable

not the stuff from the conference talk, the stuff that moved the numbers on real cheap phones

Tunde Adebayo@tunde_ade

August 10, 2026 · 3 min read

#1 in Thumb Zone

343 views5 comments

so we build a delivery and payments app for a client here in lagos and most of their users are on phones with 2 or 3GB ram, android 9 to 11, storage almost full because of whatsapp media. our app was "smooth" on the dev team phones and absolute garbage on the real ones. here is what moved the needle for us, roughly in order of how much it helped

1. stop judging performance in debug mode

sounds obvious but half the team was judging speed with flutter run in debug. debug mode is JIT and has asserts on, it will always feel slow. use flutter run --profile on a real cheap device and open devtools. if you dont own a cheap device buy one, its the best money you will spend this year

2. decode images at the size you show them

this one was the biggest win for memory. a product photo from the backend was 2000px wide and we showed it in a 120px thumbnail, and flutter was decoding the full thing into memory. multiply by a list of 50 items and android kills the app in the background. use cacheWidth / cacheHeight on Image.network (or memCacheWidth if you use cached_network_image) so it decodes small. better still, ask the backend for a thumbnail size

Image.network(
  product.imageUrl,
  width: 120,
  cacheWidth: (120 * MediaQuery.of(context).devicePixelRatio).round(),
)

3. ListView.builder for anything that can grow

we had a screen using ListView(children: [...]) with every order built upfront. builder only builds whats on screen. same for GridView.builder

4. rebuild less

  • const constructors everywhere you can, the linter will tell you where
  • split big build methods into small widgets so one setState doesnt rebuild the whole screen
  • with provider or riverpod use select, so a widget only rebuilds when the field it uses changes, not the whole object

turn on the rebuild stats in devtools and you will be shocked how much rebuilds when you type one letter in a search box

5. animations

dont animate the Opacity widget in a loop, its expensive. use FadeTransition or AnimatedOpacity. wrap things that animate all the time (like a loading shimmer) in a RepaintBoundary so they dont repaint the whole screen with them

6. app size matters more than you think

when storage is almost full people delete the biggest app first. ship app bundles so the store gives each phone only its own ABI (or --split-per-abi for apks), and build with --obfuscate --split-debug-info. our download went from a 38MB universal apk to about 14MB

none of this is magic. the real lesson is just: test on the phone your users actually have. abeg buy the cheap phone

Written by

Tunde Adebayo

Mobile dev (Flutter + React Native) at an agency in Lagos. building fintech and logistics apps mostly. if your app is slow on a 2GB android phone, its not "fine". football on weekends

Get the best of #thumb_zone weekly

One email each Monday with the most useful posts. No spam; unsubscribe in one click.

Comments

5

Sign in to join the conversation.

Sign in to comment
Mariana Costa@mari_costa#3 in Thumb Zone
The image decode part is gold. We have same problem in our checkout on web, product images 3x bigger than needed. People is downloading 4MB just to see a thumbnail. I will show this to our team.
1 net votes
Tunde Adebayo@tunde_ade#1 in Thumb Zone
yes! on web srcset does the same job, use it. mobile data here is not cheap, every MB is somebody's money
1 net votes
Chloe Barnes@chloebuilds#4 in Thumb Zone
"abeg buy the cheap phone" should be a sticker. i'll take ten
1 net votes
Tunde Adebayo@tunde_ade#1 in Thumb Zone
chloe i will design it and @mari_costa will tell me the kerning is wrong
2 net votes
Mariana Costa@mari_costa#3 in Thumb Zone
The kerning WILL be wrong, I already know
1 net votes