3 menit baca

Flutter menjanjikan 60 frame per detik, bahkan 120 di layar modern. Tapi hampir setiap developer Flutter pernah membuka aplikasinya sendiri lalu merasakan scroll yang tersendat, animasi yang patah, atau tombol yang telat merespons.
Godaan pertamanya biasanya menebak: "pasti karena gambar", "mungkin perlu state management lain". Artikel ini mengajak kebalikannya: ukur dulu, baru perbaiki.
Anggaran waktu satu frame
Di layar 60 Hz, Flutter punya sekitar 16 ms untuk menyelesaikan satu frame. Di layar 120 Hz, anggarannya tinggal 8 ms. Pekerjaan itu terbagi ke dua thread:
- UI thread menjalankan kode Dart:
build(), layout, dan logika aplikasi. - Raster thread mengubah hasilnya menjadi piksel di GPU.
Kalau salah satunya melewati anggaran, frame terlambat dan mata kita menangkapnya sebagai jank. Mengetahui thread mana yang lambat sudah separuh jalan menuju perbaikan.
Langkah 0: ukur di mode yang benar
Jangan menilai performa di mode debug. Mode debug sengaja lambat karena memakai JIT dan banyak pemeriksaan tambahan. Jalankan di perangkat asli dengan:
Lalu buka Flutter DevTools → Performance. Frame yang melewati anggaran ditandai merah, dan kamu bisa melihat apakah UI thread atau raster thread yang menjadi penyebabnya.
1. Rebuild yang terlalu luas
Penyebab paling umum:
setState() dipanggil di widget yang berada tinggi di pohon, sehingga seluruh layar ikut dibangun ulang hanya untuk mengubah satu angka.Perbaikannya adalah mempersempit bagian yang berubah, misalnya dengan
ValueListenableBuilder:Tambahkan juga
const pada widget yang tidak pernah berubah. Flutter akan melewatkan rebuild widget itu sepenuhnya.Cara membuktikan: aktifkan Track widget rebuilds di DevTools dan lihat widget mana yang dibangun ulang jauh lebih sering dari seharusnya.
2. Daftar panjang yang dibangun sekaligus
Untuk daftar yang tingginya tetap, tambahkan
itemExtent. Flutter jadi tidak perlu mengukur setiap item saat di-scroll.3. Pekerjaan berat di UI thread
Dart menjalankan kode aplikasi di satu thread. Mem-parsing JSON berukuran beberapa MB di sana akan membekukan UI selama proses berlangsung. Pindahkan ke isolate:
Kandidat lain yang layak dipindahkan: kompresi gambar, enkripsi, dan pengolahan data dalam jumlah besar.
4. Gambar yang jauh lebih besar dari tampilannya
Foto kamera 4000×3000 piksel yang ditampilkan di kotak 100×100 tetap di-decode dalam ukuran penuh. Hasilnya: memori membengkak dan raster thread bekerja keras. Minta Flutter men-decode di ukuran yang dibutuhkan saja:
5. Efek yang mahal di raster thread
Opacity, ClipRRect, dan ShaderMask pada widget besar dapat memaksa operasi saveLayer, yaitu menggambar ke layer terpisah lalu menggabungkannya kembali. Untuk animasi transparansi, gunakan FadeTransition atau AnimatedOpacity. Untuk warna semi-transparan, cukup atur warnanya langsung:Kalau DevTools menunjukkan raster thread yang merah sementara UI thread aman, mulailah mencari dari sini.
Kesimpulan
Urutannya selalu sama:
- Jalankan di mode profile pada perangkat asli.
- Cari frame yang merah di DevTools dan tentukan thread mana yang lambat.
- Perbaiki satu penyebab, lalu ukur lagi.
Optimasi tanpa pengukuran hanyalah tebakan yang membuat kode lebih rumit. Dengan pengukuran, kamu tahu persis bagian mana yang layak diperbaiki.
