# Optimasi Performa Flutter pada 2026: Impeller, Rebuild, dan Praktik Terbaik > Cara menjaga aplikasi Flutter pada 60 atau 120 fps yang stabil pada 2026 dengan Impeller, rebuild widget yang disiplin, RepaintBoundary, dan profiling DevTools. - Published: 2026-07-04 - Updated: 2026-07-07 - Author: SharpSkill - Tags: flutter, performance, impeller, best-practices, dart, mobile - Reading time: 9 min --- Optimasi performa Flutter pada 2026 bertumpu pada dua pergeseran yang mengubah cara aplikasi mulus dibangun: mesin rendering Impeller kini aktif secara default di iOS dan Android, dan model rebuild framework memberi keuntungan bagi pengembang yang menjaga pohon widget tetap kecil dan tidak berubah. Tim yang memanfaatkan kedua tuas ini menahan 60 atau 120 fps yang stabil tanpa menyetel setiap frame secara manual. > **Perubahan dengan dampak terbesar** > > Keuntungan terbesar di sebagian besar aplikasi Flutter adalah menambahkan konstruktor `const` dan memecah metode `build` yang besar, sehingga panggilan `setState` menggambar ulang satu tombol alih-alih seluruh layar. ## Mengapa Impeller mengatur ulang garis dasar performa Flutter Impeller adalah mesin rendering Flutter, dan ia menggantikan Skia sebagai default di seluruh platform seluler. Perbedaannya paling terasa pada detik-detik pertama sebuah animasi. Skia mengompilasi shader-nya secara just-in-time, saat suatu efek pertama kali muncul di layar, yang menghasilkan gagap pertama-jalan yang terkenal, yang kerap dikritik pada aplikasi Flutter. Impeller mengompilasi shader itu di awal, saat build, sehingga frame pertama sebuah animasi semulus frame keseratus. Impeller juga membidik langsung API grafis modern: Metal di iOS dan Vulkan di Android, dengan cadangan OpenGL untuk perangkat keras Android yang lebih lama. [Dokumentasi mesin Impeller di GitHub](https://github.com/flutter/flutter/blob/master/docs/engine/impeller/README.md) merinci arsitektur rendering dan matriks dukungan platform. | Aspek | Skia (lawas) | Impeller (default 2026) | |--------|---------------|-------------------------| | Kompilasi shader | Saat runtime, memicu gagap pada jalan pertama | Di awal, saat build | | Backend iOS | OpenGL / Metal | Metal | | Backend Android | OpenGL | Vulkan, cadangan OpenGL | | Kemulusan animasi pertama | Sesekali gagap | Konsisten | Bagi sebagian besar proyek, migrasinya gratis: rilis Flutter terbaru mengaktifkan Impeller secara otomatis, dan solusi lama untuk pemanasan shader (`--purge-persistent-cache`, berkas `.sksl` yang dibundel) tidak lagi diperlukan dan dapat dihapus. Shader `FragmentProgram` kustom yang ditulis terhadap subset GLSL yang didukung Flutter juga tetap berfungsi, karena Impeller mengompilasinya melalui pipeline offline yang sama dengan efek bawaan framework. Memverifikasi mesin mana yang menjalankan aplikasi hanya butuh satu baris: build debug mencetak backend aktif saat mulai, dan inspektor DevTools melaporkannya di detail rendering aplikasi. Setelah Impeller dikonfirmasi, sisa pekerjaan performa naik ke lapisan widget, tempat framework melakukan rebuild jauh lebih sering daripada perubahan layar yang sebenarnya. Di situlah sisa panduan ini berfokus, karena mesin yang cepat tidak dapat menyelamatkan pohon widget yang menggambar ulang dirinya ratusan kali per detik. ## Menekan rebuild Flutter dengan const dan pemecahan widget Setiap `setState` menandai widget-nya sebagai usang dan menjalankan ulang `build` untuk elemen itu beserta subpohonnya. Triknya adalah menjaga subpohon itu sesempit mungkin. Dua kebiasaan melakukan sebagian besar pekerjaan: menandai widget statis sebagai `const`, dan mendorong state ke bawah agar bagian yang berstate tetap kecil. Widget `const` dikanonikalisasi menjadi satu instans, sehingga ketika induk melakukan rebuild, Flutter membandingkan referensi yang identik, tidak melihat perubahan, dan sepenuhnya melewati penggambaran ulang cabang itu. ```dart // product_screen.dart // A cart update repaints the badge, not the header. class ProductScreen extends StatefulWidget { const ProductScreen({super.key}); @override State createState() => _ProductScreenState(); } class _ProductScreenState extends State { int _cartCount = 0; @override Widget build(BuildContext context) { return Column( children: [ const ProductHeader(), // const: never rebuilds on setState CartBadge(count: _cartCount), // only this subtree rebuilds FilledButton( onPressed: () => setState(() => _cartCount++), child: const Text('Add to cart'), ), ], ); } } ``` Mengaktifkan lint `prefer_const_constructors` di `analysis_options.yaml` mengubah disiplin ini menjadi pemeriksaan kompiler, sehingga peluang `const` tidak pernah mundur secara diam-diam. Aturan terkait `prefer_const_literals_to_create_immutables` memperluas jaminan yang sama ke list dan map yang diteruskan ke widget. Key widget juga layak disebut di sini. Ketika sebuah list diurutkan ulang atau sebuah widget tetap bertipe sama tetapi identitasnya berubah, `ValueKey` atau `ObjectKey` memungkinkan Flutter mencocokkan elemen lama dengan instans widget baru yang tepat alih-alih membongkar dan membangun ulang state. Key yang hilang adalah penyebab umum posisi gulir yang lenyap dan animasi yang tereset di list dinamis, dan pekerjaan rebuild ekstra yang ditimbulkannya mudah terlewatkan. ## Membatasi rebuild pada data yang berubah Ketika state berada tinggi di pohon, bahkan tata letak yang terpecah rapi pun tetap banyak melakukan rebuild. Perbaikannya adalah menyiarkan sebuah nilai dan membiarkan satu widget menyimaknya. Flutter menyediakan `ValueNotifier` dan `ValueListenableBuilder` khusus untuk ini, tanpa paket eksternal. ```dart // article_list.dart // A scroll-to-top button that rebuilds alone, not the whole page. class ArticleList extends StatefulWidget { const ArticleList({super.key}); @override State createState() => _ArticleListState(); } class _ArticleListState extends State { final _showFab = ValueNotifier(false); final _controller = ScrollController(); @override void initState() { super.initState(); // Update the notifier, not setState: the list never rebuilds _controller.addListener(() => _showFab.value = _controller.offset > 400); } @override void dispose() { _showFab.dispose(); _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: ListView.builder( controller: _controller, itemCount: 200, itemBuilder: (_, i) => ListTile(title: Text('Item $i')), ), floatingActionButton: ValueListenableBuilder( valueListenable: _showFab, builder: (_, visible, __) => visible ? FloatingActionButton( onPressed: () => _controller.jumpTo(0), child: const Icon(Icons.arrow_upward), ) : const SizedBox.shrink(), ), ); } } ``` Pustaka manajemen state menggeneralisasi ide yang sama. `ref.watch(provider.select(...))` milik Riverpod dan widget `Selector` dari Provider sama-sama hanya melakukan rebuild ketika irisan state yang dipilih berubah, yang menjadi faktor penentu antara mulus dan tersendat di layar yang padat data. Pertukaran antara pustaka-pustaka itu dibahas dalam panduan [manajemen state Flutter pada 2026](/blog/flutter/flutter-state-management-2026-riverpod-bloc-getx). > **Perhatikan cakupan rebuild** > > Memanggil `setState` di dekat akar sebuah layar, atau membungkus seluruh halaman dalam `Consumer` tingkat atas, diam-diam menggambar ulang ratusan widget pada setiap perubahan. Lakukan profiling dengan penghitung rebuild di DevTools sebelum menganggap sebuah layar itu murah. ## Mengisolasi repaint yang mahal dengan RepaintBoundary Rebuild dan repaint adalah tahap yang terpisah. Sebuah widget dapat melewati rebuild namun tetap repaint karena tetangga yang ramai berbagi layer-nya. `RepaintBoundary` memberi subpohon layer-nya sendiri, sehingga grafik beranimasi tidak dapat memaksa kartu statis menggambar ulang setiap frame. ```dart // dashboard.dart // The live chart repaints on its own layer, cards stay untouched. class Dashboard extends StatelessWidget { const Dashboard({required this.ticker, super.key}); final Stream ticker; @override Widget build(BuildContext context) { return Column( children: [ // SummaryCards is static, so isolate it from the animation below const RepaintBoundary(child: SummaryCards()), RepaintBoundary( child: StreamBuilder( stream: ticker, builder: (_, snap) => LivePriceChart(value: snap.data ?? 0), ), ), ], ); } } ``` RepaintBoundary tidak gratis: masing-masing mengalokasikan sebuah layer, sehingga menaburkannya di mana-mana lebih banyak merugikan daripada membantu. Gunakan di sekitar wilayah yang benar-benar beranimasi dan list panjang yang bergulir, lalu konfirmasi keuntungannya di timeline. [Referensi API RepaintBoundary](https://api.flutter.dev/flutter/widgets/RepaintBoundary-class.html) mendokumentasikan bagaimana overlay repaint debug menyoroti layer mana yang benar-benar digambar ulang. ## Menjaga metode build tetap murah dan tanpa efek samping Metode `build` berjalan pada setiap rebuild, sehingga apa pun yang mahal di dalamnya berlipat ganda. Aturannya adalah `build` harus membaca state dan mengembalikan widget, tidak lebih. Mengalokasikan `ScrollController`, `AnimationController`, atau `Future` di dalam `build` membuatnya ulang pada setiap frame dan membocorkan instans sebelumnya. Objek-objek itu tempatnya di `initState` atau di field `late final`, yang dibebaskan di `dispose`. Pekerjaan sinkron yang berat adalah jebakan kedua. Mengurai JSON, memfilter list yang besar, atau memformat tanggal di dalam `build` menjalankan ulang pekerjaan itu pada setiap repaint, bahkan ketika data yang mendasarinya tidak berubah. Hitung hasilnya sekali ketika input berubah lalu simpan di cache, atau pindahkan ke `FutureBuilder` agar framework tidak memblokir sebuah frame sambil menunggunya. Untuk nilai yang diturunkan dari nilai lain, memoize di balik getter yang hanya menghitung ulang ketika dependensinya berubah. Widget `Opacity` adalah biang keladi spesifik yang layak disebut. Membungkus subpohon dalam `Opacity` memaksa `saveLayer` di luar layar, salah satu operasi termahal dalam pipeline. Untuk animasi pudar, `AnimatedOpacity` atau `FadeTransition` lebih murah, dan untuk warna tetap, menerapkan warna pada tingkat paint melalui `foregroundDecoration` atau shader sepenuhnya menghindari layer itu. Kehati-hatian yang sama berlaku untuk `ClipPath` dan `ClipRRect` dengan anti-aliasing pada permukaan besar, yang juga memicu `saveLayer` di balik layar. Terakhir, utamakan koleksi `const` dan callback yang tidak menangkap closure baru pada setiap build. Sebuah `const []` yang diteruskan sebagai default dan referensi metode alih-alih lambda inline sama-sama menjaga pemeriksaan kesetaraan widget tetap murah, yang membuat korsleting `const` yang dijelaskan sebelumnya benar-benar terpicu. ## Membangun list panjang dan gambar secara efisien Feed panjang dan grid gambar adalah tempat kode Flutter yang naif menjatuhkan frame. Dua aturan mencakup sebagian besar kasus: membangun baris secara malas, dan mendekode gambar pada ukuran tampilnya alih-alih resolusi sumbernya. ```dart // feed.dart // Lazy rows plus right-sized image decoding keep scrolling at 60fps. class Feed extends StatelessWidget { const Feed({required this.posts, super.key}); final List posts; @override Widget build(BuildContext context) { return ListView.builder( itemCount: posts.length, // build on demand, not all at once cacheExtent: 600, // pre-build past the viewport edge itemBuilder: (context, index) { final post = posts[index]; return ListTile( leading: Image.network( post.thumbnailUrl, width: 48, height: 48, cacheWidth: 96, // decode at display size, save memory ), title: Text(post.title), ); }, ); } } ``` Gambar resolusi penuh 3000 piksel yang dijejalkan ke avatar 48 piksel memboroskan memori dan waktu dekode pada setiap gambar. Menetapkan `cacheWidth` memberi tahu mesin untuk mendekode pada ukuran target, yang saja dapat memangkas jejak memori sebuah list sebesar satu orde besaran. [Praktik terbaik performa](https://docs.flutter.dev/perf/best-practices) Flutter mengumpulkan panduan lanjutan tentang `Opacity`, `saveLayer`, dan penggunaan clip yang mengikuti prinsip yang sama. ## Mengukur optimasi Flutter pada 2026 dengan DevTools Setiap aturan di atas harus diverifikasi, bukan diasumsikan. Flutter DevTools adalah sumber kebenaran. Overlay performa (`P` di konsol debug, atau `flutter run --profile`) menggambar dua grafik, UI dan raster, dan setiap batang yang melewati garis hijau adalah frame yang jatuh. Tampilan timeline kemudian mengatribusikan setiap frame lambat ke panggilan `build`, layout, atau paint yang spesifik. Selalu lakukan profiling dalam mode `--profile` pada perangkat fisik. Build debug menjalankan Dart yang tidak dioptimalkan dan menggembungkan setiap pengukuran, sehingga layar yang tersendat saat debug sering berjalan sempurna setelah dikompilasi. [Panduan performa DevTools](https://docs.flutter.dev/tools/devtools/performance) memandu cara membaca bagan frame dan menemukan sumber jank, dan otot profiling yang sama muncul dalam wawancara tentang [animasi dan rendering Flutter](/technologies/flutter/interview-questions/animations). > **Siklus profiling cepat** > > Jalankan dalam mode profile, reproduksi interaksi yang tersendat, buka timeline, dan urutkan frame berdasarkan durasi. Frame terburuk hampir selalu menunjuk ke satu rebuild yang kelewat besar atau gambar yang tidak di-cache, yang jauh lebih cepat daripada menebak. [Hub teknologi Flutter](/technologies/flutter) menautkan topik manajemen state, pengujian, dan rendering yang melengkapi strategi performa produksi. ## Kesimpulan Performa Flutter pada 2026 lebih sedikit soal trik mikro dan lebih banyak soal daftar pendek kebiasaan yang diterapkan secara konsisten: - Rilis di atas Impeller dan hapus kode pemanasan shader lawas; masalah jank frame pertama sudah terpecahkan di tingkat mesin. - Tandai widget statis sebagai `const` dan tegakkan dengan lint `prefer_const_constructors`. - Pecah widget berstate menjadi kecil, agar setiap `setState` menggambar ulang subpohon sesempit mungkin. - Siarkan nilai yang berubah melalui `ValueListenableBuilder` atau API bergaya `select` alih-alih membangun ulang seluruh layar. - Bungkus wilayah yang benar-benar beranimasi dalam `RepaintBoundary`, tetapi ukur sebelum menambah lebih banyak. - Bangun list dengan `ListView.builder` dan dekode gambar pada ukuran tampilan menggunakan `cacheWidth`. - Lakukan profiling dalam mode `--profile` pada perangkat keras nyata dan biarkan DevTools, bukan intuisi, yang memutuskan apa yang dioptimalkan berikutnya. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/id/blog/flutter/flutter-performance-optimization-2026-impeller-rebuilds