Flutter'da Performans Optimizasyonu 2026: Impeller, Yeniden Oluşturmalar ve En İyi Uygulamalar

Flutter uygulamalarını 2026'da Impeller, disiplinli widget yeniden oluşturmaları, RepaintBoundary ve DevTools profillemesiyle sabit 60 veya 120 fps'de tutmanın yolu.

Impeller ve azaltılmış widget yeniden oluşturmalarıyla Flutter performans optimizasyonu

Flutter'da 2026'da performans optimizasyonu, akıcı uygulamaların nasıl kurulduğunu değiştiren iki dönüşüme dayanır: Impeller render motoru artık iOS ve Android'de varsayılan olarak gelir ve framework'ün yeniden oluşturma modeli, widget ağaçlarını küçük ve değişmez tutan geliştiricileri ödüllendirir. Her iki kaldıraçtan da yararlanan ekipler, her kareyi elle ayarlamadan sabit 60 veya 120 fps'yi korur.

En yüksek etkili değişiklik

Çoğu Flutter uygulamasındaki en büyük kazanç, const yapıcılar eklemek ve büyük build yöntemlerini bölmektir; böylece bir setState çağrısı tüm ekran yerine tek bir düğmeyi yeniden çizer.

Impeller, Flutter performans referansını neden yeniden belirliyor

Impeller, Flutter'ın render motorudur ve mobil platformlarda varsayılan olarak Skia'nın yerini almıştır. Fark en çok bir animasyonun ilk saniyelerinde önemlidir. Skia, shader'larını tam zamanında, belirli bir efekt ekranda ilk kez göründüğünde derliyordu; bu da Flutter uygulamalarının eleştirildiği o meşhur ilk çalıştırma takılmasını üretiyordu. Impeller bu shader'ları önceden, derleme sırasında derler; böylece bir animasyonun ilk karesi yüzüncüsü kadar akıcıdır.

Impeller ayrıca doğrudan modern grafik API'lerini hedefler: iOS'ta Metal, Android'de Vulkan ve eski Android donanımı için OpenGL yedeği. GitHub'daki Impeller motoru belgeleri render mimarisini ve platform destek matrisini ayrıntılı olarak anlatır.

| Yön | Skia (eski) | Impeller (2026 varsayılanı) | |--------|---------------|-------------------------| | Shader derlemesi | Çalışma zamanında, ilk çalıştırmada takılmaya neden olur | Önceden, derlemede | | iOS arka ucu | OpenGL / Metal | Metal | | Android arka ucu | OpenGL | Vulkan, OpenGL yedeği | | İlk animasyonun akıcılığı | Ara sıra takılma | Sabit |

Çoğu proje için geçiş bedavadır: Yeni Flutter sürümleri Impeller'ı otomatik olarak etkinleştirir ve eski shader ısıtma geçici çözümleri (--purge-persistent-cache, paketlenmiş .sksl dosyaları) artık gerekli değildir ve silinebilir. Flutter'ın desteklediği GLSL alt kümesine göre yazılmış özel FragmentProgram shader'ları da çalışmaya devam eder, çünkü Impeller bunları framework'ün kendi efektleriyle aynı çevrimdışı işlem hattından derler.

Bir uygulamanın hangi motorda çalıştığını doğrulamak tek satır alır: bir hata ayıklama derlemesi başlangıçta etkin arka ucu yazdırır ve DevTools denetçisi bunu uygulamanın render ayrıntılarında bildirir. Impeller doğrulandıktan sonra kalan performans işi, framework'ün ekranın gerçekte değiştiğinden çok daha sık yeniden oluşturduğu widget katmanına yükselir. Bu kılavuzun geri kalanı buna odaklanır, çünkü hızlı bir motor, kendini saniyede yüzlerce kez yeniden çizen bir widget ağacını kurtaramaz.

const ve widget bölme ile Flutter yeniden oluşturmalarını azaltma

Her setState, widget'ını kirli olarak işaretler ve o eleman ile alt ağacı için build'i yeniden çalıştırır. İşin sırrı, o alt ağacı olabildiğince dar tutmaktır. İki alışkanlık işin çoğunu yapar: statik widget'ları const olarak işaretlemek ve durumu aşağıya iterek durumlu kısmı küçük tutmak.

Bir const widget tek bir örneğe kanonikleştirilir; böylece bir ebeveyn yeniden oluştuğunda Flutter aynı referansı karşılaştırır, hiçbir değişiklik görmez ve o dalın yeniden çizilmesini tamamen atlar.

product_screen.dartdart
// A cart update repaints the badge, not the header.

class ProductScreen extends StatefulWidget {
  const ProductScreen({super.key});

  
  State<ProductScreen> createState() => _ProductScreenState();
}

class _ProductScreenState extends State<ProductScreen> {
  int _cartCount = 0;

  
  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'),
        ),
      ],
    );
  }
}

analysis_options.yaml içinde prefer_const_constructors lint'ini etkinleştirmek bu disiplini bir derleyici denetimine dönüştürür; böylece const fırsatları asla sessizce geri gitmez. İlgili prefer_const_literals_to_create_immutables kuralı aynı garantiyi widget'lara geçirilen listelere ve haritalara genişletir.

Widget anahtarları da burada anılmayı hak eder. Bir liste yeniden sıralandığında ya da bir widget aynı türü korurken kimliği değiştiğinde, bir ValueKey veya ObjectKey, Flutter'ın eski elemanı doğru yeni widget örneğiyle eşleştirmesini sağlar; durumu yıkıp yeniden oluşturmak yerine. Anahtar eksikliği, dinamik listelerde kayan konum kaybının ve sıfırlanan animasyonların yaygın bir nedenidir ve neden olduğu ek yeniden oluşturma işini gözden kaçırmak kolaydır.

Yeniden oluşturmaları değişen veriyle sınırlama

Durum ağacın yukarısında yaşadığında, iyi bölünmüş bir düzen bile çokça yeniden oluşur. Çözüm, bir değeri yayınlamak ve tek bir widget'ın onu dinlemesine izin vermektir. Flutter, tam bu amaçla ValueNotifier ve ValueListenableBuilder sağlar; harici bir paket gerekmez.

article_list.dartdart
// A scroll-to-top button that rebuilds alone, not the whole page.

class ArticleList extends StatefulWidget {
  const ArticleList({super.key});

  
  State<ArticleList> createState() => _ArticleListState();
}

class _ArticleListState extends State<ArticleList> {
  final _showFab = ValueNotifier<bool>(false);
  final _controller = ScrollController();

  
  void initState() {
    super.initState();
    // Update the notifier, not setState: the list never rebuilds
    _controller.addListener(() => _showFab.value = _controller.offset > 400);
  }

  
  void dispose() {
    _showFab.dispose();
    _controller.dispose();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView.builder(
        controller: _controller,
        itemCount: 200,
        itemBuilder: (_, i) => ListTile(title: Text('Item $i')),
      ),
      floatingActionButton: ValueListenableBuilder<bool>(
        valueListenable: _showFab,
        builder: (_, visible, __) => visible
            ? FloatingActionButton(
                onPressed: () => _controller.jumpTo(0),
                child: const Icon(Icons.arrow_upward),
              )
            : const SizedBox.shrink(),
      ),
    );
  }
}

Durum yönetimi kütüphaneleri aynı fikri genelleştirir. Riverpod'un ref.watch(provider.select(...)) ifadesi ve Provider'ın Selector widget'ı yalnızca durumun seçilen bir dilimi değiştiğinde yeniden oluşur; bu da veri yoğun ekranlarda akıcı ile takılmalı arasındaki belirleyici etkendir. Bu kütüphaneler arasındaki ödünleşimler Flutter'da 2026'da durum yönetimi kılavuzunda ele alınır.

Yeniden oluşturma kapsamına dikkat

Bir ekranın köküne yakın setState çağırmak ya da tüm bir sayfayı üst düzey bir Consumer içine sarmak, her değişiklikte sessizce yüzlerce widget'ı yeniden çizer. Bir ekranın ucuz olduğunu varsaymadan önce DevTools'taki yeniden oluşturma sayacıyla profil çıkarın.

Flutter mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

Pahalı yeniden çizimleri RepaintBoundary ile izole etme

Yeniden oluşturmak ve yeniden çizmek ayrı aşamalardır. Bir widget yeniden oluşturmayı atlayıp yine de yeniden çizilebilir, çünkü gürültülü bir komşu onun katmanını paylaşır. RepaintBoundary bir alt ağaca kendi katmanını verir; böylece animasyonlu bir grafik, statik kartları her karede yeniden çizmeye zorlayamaz.

dashboard.dartdart
// The live chart repaints on its own layer, cards stay untouched.

class Dashboard extends StatelessWidget {
  const Dashboard({required this.ticker, super.key});
  final Stream<double> ticker;

  
  Widget build(BuildContext context) {
    return Column(
      children: [
        // SummaryCards is static, so isolate it from the animation below
        const RepaintBoundary(child: SummaryCards()),
        RepaintBoundary(
          child: StreamBuilder<double>(
            stream: ticker,
            builder: (_, snap) => LivePriceChart(value: snap.data ?? 0),
          ),
        ),
      ],
    );
  }
}

RepaintBoundary bedava değildir: her biri bir katman ayırır, bu yüzden onu her yere serpiştirmek yardımdan çok zarar verir. Gerçekten animasyonlu bölgeler ve uzun kaydırılan listeler için kullanın ve kazancı zaman çizelgesinde doğrulayın. RepaintBoundary API başvurusu hata ayıklama yeniden çizim katmanının hangi katmanların gerçekten yeniden çizildiğini nasıl vurguladığını belgeler.

build yöntemini ucuz ve yan etkisiz tutma

Bir build yöntemi her yeniden oluşturmada çalışır, bu yüzden içindeki pahalı her şey çoğalır. Kural, build'in durumu okuyup widget döndürmesidir, fazlası değil. build içinde bir ScrollController, AnimationController veya Future ayırmak onu her karede yeniden oluşturur ve önceki örneği sızdırır. Bu nesneler initState'e ya da dispose içinde serbest bırakılan bir late final alana aittir.

Ağır senkron iş ikinci tuzaktır. build içinde JSON ayrıştırmak, büyük bir listeyi filtrelemek veya tarihleri biçimlendirmek, temeldeki veri değişmese bile bu işi her yeniden çizimde tekrar çalıştırır. Girdi değiştiğinde sonucu bir kez hesaplayıp önbelleğe alın ya da framework'ün onu beklerken bir kareyi engellememesi için bir FutureBuilder içine taşıyın. Başka değerlerden türetilen değerler için, bunları yalnızca bağımlılıkları değiştiğinde yeniden hesaplayan bir getter arkasında bellekleyin.

Opacity widget'ı adı anılmayı hak eden belirli bir suçludur. Bir alt ağacı Opacity içine sarmak ekran dışı bir saveLayer'ı zorlar; bu, işlem hattındaki en pahalı işlemlerden biridir. Bir solma animasyonu için AnimatedOpacity ya da bir FadeTransition daha ucuzdur ve sabit bir renk tonu için rengi bir foregroundDecoration veya shader aracılığıyla boya düzeyinde uygulamak katmandan tamamen kaçınır. Aynı dikkat, büyük yüzeylerde kenar yumuşatmalı ClipPath ve ClipRRect için de geçerlidir; bunlar da perde arkasında bir saveLayer tetikler.

Son olarak, const koleksiyonları ve her yapımda yeni kapanışlar yakalamayan geri çağırmaları tercih edin. Varsayılan olarak geçirilen bir const [] ve satır içi bir lambda yerine bir yöntem referansı, widget eşitlik denetimlerini ucuz tutar; bu da daha önce anlatılan const kısa devresinin gerçekten tetiklenmesini sağlar.

Uzun listeleri ve görselleri verimli oluşturma

Uzun akışlar ve görsel ızgaraları, saf Flutter kodunun kare düşürdüğü yerdir. İki kural çoğu durumu kapsar: satırları tembel oluşturmak ve görselleri kaynak çözünürlüğünde değil, gösterildikleri boyutta çözmek.

feed.dartdart
// Lazy rows plus right-sized image decoding keep scrolling at 60fps.

class Feed extends StatelessWidget {
  const Feed({required this.posts, super.key});
  final List<Post> posts;

  
  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),
        );
      },
    );
  }
}

48 piksellik bir avatara sıkıştırılmış tam çözünürlüklü 3000 piksellik bir görsel, her biri için bellek ve kod çözme süresi harcar. cacheWidth ayarlamak motora hedef boyutta çözmesini söyler; bu tek başına bir listenin bellek ayak izini bir büyüklük derecesi azaltabilir. Flutter'ın performans en iyi uygulamaları aynı ilkeyi izleyen Opacity, saveLayer ve kırpma kullanımına dair daha fazla rehberliği bir araya getirir.

2026'da Flutter optimizasyonunu DevTools ile ölçme

Yukarıdaki her kural varsayılmamalı, doğrulanmalıdır. Flutter DevTools gerçeğin kaynağıdır. Performans katmanı (hata ayıklama konsolunda P ya da flutter run --profile) iki grafik çizer, UI ve raster, ve yeşil çizgiyi aşan her çubuk düşen bir karedir. Zaman çizelgesi görünümü sonra her yavaş kareyi belirli bir build, düzen veya boyama çağrısına atfeder.

Her zaman fiziksel bir cihazda --profile modunda profil çıkarın. Hata ayıklama derlemeleri optimize edilmemiş Dart çalıştırır ve her ölçümü şişirir; bu yüzden hata ayıklamada takılan bir ekran çoğu zaman derlendikten sonra kusursuz çalışır. DevTools performans kılavuzu kare grafiğini okumayı ve takılma kaynaklarını saptamayı adım adım anlatır ve aynı profilleme kası Flutter animasyonları ve render üzerine mülakatlarda da ortaya çıkar.

Hızlı bir profilleme döngüsü

Profile modunda çalıştırın, takılan etkileşimi yeniden üretin, zaman çizelgesini açın ve kareleri süreye göre sıralayın. En kötü kare neredeyse her zaman tek bir aşırı büyük yeniden oluşturmaya ya da önbelleğe alınmamış bir görsele işaret eder; bu, tahmin etmekten çok daha hızlıdır.

Flutter teknoloji merkezi, üretim düzeyinde bir performans stratejisini tamamlayan durum yönetimi, test ve render konularını birbirine bağlar.

Sonuç

2026'da Flutter performansı, mikro numaralardan çok, tutarlı biçimde uygulanan kısa bir alışkanlık listesiyle ilgilidir:

  • Impeller üzerinde dağıtın ve eski shader ısıtma kodunu silin; ilk kare takılması sorunu motor düzeyinde çözülmüştür.
  • Statik widget'ları const olarak işaretleyin ve bunu prefer_const_constructors lint'iyle zorunlu kılın.
  • Durumlu widget'ları küçük parçalara bölün, böylece her setState mümkün olan en dar alt ağacı yeniden çizer.
  • Değişen değerleri tüm ekranları yeniden oluşturmak yerine ValueListenableBuilder ya da select tarzı bir API aracılığıyla yayınlayın.
  • Gerçekten animasyonlu bölgeleri bir RepaintBoundary içine sarın, ama daha fazlasını eklemeden önce ölçün.
  • Listeleri ListView.builder ile oluşturun ve görselleri cacheWidth kullanarak gösterim boyutunda çözün.
  • Gerçek donanımda --profile modunda profil çıkarın ve sırada neyi optimize edeceğinize sezgiye değil DevTools'a karar verdirin.

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Etiketler

#flutter
#performance
#impeller
#best-practices
#dart
#mobile

Paylaş

İlgili makaleler