Flutter

Flutter Performans Optimizasyonu: Kapsamlı Rehber

14 dk okuma9 Şubat 2026Güncellendi 9 Mar 2026
Flutter performanceFlutter optimizasyonFlutter hızlandırmaFlutter widget rebuildFlutter memoryFlutter profilingFlutter DevToolsFlutter best practicesFlutter lag fix

Performans calismasi her zaman veriye dayali olmalidir. Darbogazlarin nerede oldugunu tahmin etmek, bos yere zaman harcamaktir. Bu rehberde, takilmali bir Flutter uygulamasini akici bir 60fps (hatta 120fps) deneyime donusturecek teknikleri, araclari ve yaklasim degisikliklerini ele aliyorum.

Performans Neden Onemlidir

Kullanicilar fark eder. Arastirmalar, arayuz yanitindaki 100ms'lik bir gecikmenin hissedilir yavaslik yarattigi, 300ms'yi asan gecikmelerin ise uygulamanin bozuk oldugu izlenimini verdigi gosteriyor. Flutter'da tek bir dusuk kare bile render hattinin 16ms butcesini (60Hz'de) astigi anlamina gelir. Bunu kaydirma, sayfa gecisleri ve animasyonlarla carptiginizda, ozellikler ne kadar iyi olursa olsun uygulamaniz ucuz hissettirir.

En Kritik 10 Performans Katili (ve Cozumleri)

1. Tum Widget Agacini Yeniden Olusturmak

Uretim kod tabanlarinda en sik karsilastigim sorun budur. Buyuk bir widget agacinin tepesinde yapilan tek bir setState cagrisi, tum alt dallaarin yeniden olusturulmasini tetikler.

Yanlis yaklasim:

dart
class MyHomePage extends StatefulWidget {
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          // Bu pahali widget, _counter her degistiginde yeniden olusturulur
          ExpensiveHeader(),
          ExpensiveProductList(),
          Text('Sayac: $_counter'),
          ElevatedButton(
            onPressed: () => setState(() => _counter++),
            child: Text('Artir'),
          ),
        ],
      ),
    );
  }
}

Cozum: Degisen kismi ayri bir widget'a cikarin.

dart
class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          const ExpensiveHeader(),
          const ExpensiveProductList(),
          // Sadece bu kucuk widget yeniden olusturulur
          CounterDisplay(),
        ],
      ),
    );
  }
}

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

  @override
  State<CounterDisplay> createState() => _CounterDisplayState();
}

class _CounterDisplayState extends State<CounterDisplay> {
  int _counter = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('Sayac: $_counter'),
        ElevatedButton(
          onPressed: () => setState(() => _counter++),
          child: Text('Artir'),
        ),
      ],
    );
  }
}

2. const Constructor Kullanmamak

const olmayan her widget, her build'de yeni bir ornek olarak olusturulur. Framework bunu onceki agacla karsilastirmak zorundadir. const ile Flutter, widget'in degismedigini bilir ve tamamen atlar.

dart
// Yanlis - her build'de yeni ornek
Container(
  padding: EdgeInsets.all(16),
  child: Text('Merhaba'),
)

// Dogru - derleme zamani sabiti, rebuild sirasinda atlanir
const Padding(
  padding: EdgeInsets.all(16),
  child: Text('Merhaba'),
)

3. Tum Liste Elemanlarini Aninda Olusturmak

Yuzlerce eleman iceren ListView(children: [...]) kullanmak, ekran disinda kalanlar dahil hepsinin ayni anda olusturulup yerlestirilmesi demektir.

dart
// Yanlis - 10.000 elemanin hepsini aninda olusturur
ListView(
  children: List.generate(10000, (i) => ProductCard(product: products[i])),
)

// Dogru - sadece gorunen elemanlari ve kucuk bir tamponu olusturur
ListView.builder(
  itemCount: products.length,
  itemBuilder: (context, i) => ProductCard(product: products[i]),
)

4. Optimize Edilmemis Gorseller

4000x3000 piksellik bir gorseli 200x150'lik bir widget'a yuklemek muazzam miktarda bellek ve kod cozme suresi israf eder.

dart
// Yanlis - tam cozunurluk bellege yuklenir
Image.network('https://example.com/buyuk-foto.jpg')

// Dogru - sadece ihtiyaciniz kadari cozumlenir
Image.network(
  'https://example.com/buyuk-foto.jpg',
  cacheWidth: 400,  // Retina icin goruntuleme genisliginin 2 kati
  cacheHeight: 300,
)

5. UI Isolate Uzerinde Agir Islemler

Buyuk bir JSON yanitini parse etmek, gorsel islemek veya kriptografi islemleri calistirmak ana isolate'i bloke ederek render hattini durdurur.

dart
// Yanlis - arayuzu bloke eder
final data = jsonDecode(devJsonString);

// Dogru - ayri bir isolate'e yikle
final data = await compute(jsonDecode, devJsonString);

Daha karmasik isler icin Isolate.spawn veya IsolatePool kalibini kullanin.

6. Opacity ve ColorFiltered'in Asiri Kullanimi

Opacity widget'i ayri bir compositing katmani olusturur. Ic ice veya buyuk alt agaclarda kullanildiginda GPU performansini olturur.

dart
// Yanlis - tum alt agac icin offscreen buffer olusturur
Opacity(
  opacity: 0.5,
  child: BuyukKarmasikWidget(),
)

// Daha iyi - sadece metin/ikon saydamligina ihtiyaciniz varsa
Text('Merhaba', style: TextStyle(color: Colors.black.withOpacity(0.5)))

7. RepaintBoundary Kullanmamak

Repaint sinirlari olmadan, kucuk bir animasyon her karede tum ekranin yeniden boyanmasina neden olabilir.

dart
// Sik degisen widget'lari sarin
RepaintBoundary(
  child: AnimatedProgressIndicator(),
)

8. Pahali build() Metodlari

build() icinde filtreleme, siralama veya hesaplama yapmak, bunlarin her rebuild'de calisacagi anlamina gelir.

dart
// Yanlis - her build'de siralar
@override
Widget build(BuildContext context) {
  final sorted = List.of(items)..sort((a, b) => a.date.compareTo(b.date));
  return ListView.builder(
    itemCount: sorted.length,
    itemBuilder: (ctx, i) => ItemTile(sorted[i]),
  );
}

// Dogru - veri degistiginde sirala, sonucu onbellekle
late List<Item> _sortedItems;

void _updateItems(List<Item> items) {
  _sortedItems = List.of(items)..sort((a, b) => a.date.compareTo(b.date));
  setState(() {});
}

9. Shader Derleme Takilmalarini Goz Ardi Etmek

Flutter yeni bir shader ile ilk kez karsilastiginda, onu aninda derler ve gorunur bir takilma yaratir. Bu ozellikle ilk acilista belirgindir.

Cozum: Isinma sureci sirasinda flutter run --profile --cache-sksl --purge-persistent-cache kullanin, ardindan yakalanan shader'lari --bundle-sksl-path ile paketleyin.

10. Kisitlanmamis Intrinsic Hesaplamalari

IntrinsicHeight ve IntrinsicWidth en kotu durumda O(n^2) karmasikligindadir, cunku spekulatif bir yerlestirme gecisi yaparlar. Listelerde kullanmaktan kacinin.

dart
// ListView icinde yanlis
IntrinsicHeight(
  child: Row(
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: [LeftPanel(), RightPanel()],
  ),
)

// Daha iyi - sabit yukseklik veya LayoutBuilder kullanin
SizedBox(
  height: 120,
  child: Row(
    children: [LeftPanel(), RightPanel()],
  ),
)

DevTools ile Profilleme Rehberi

Flutter DevTools en iyi dostunuzdur. Her performans sorusturmasinda izledigim pratik is akisini paylasiyorum.

Adim 1: Profile Modunda Calistirin

bash
flutter run --profile

Asla debug modunda profilleme yapmayin. Debug modu tum optimizasyonlari devre disi birakir ve yaniltici rakamlar verir. Profile modu, tipiik release gibi AOT derleme kullanir, ancak observatory ve DevTools baglantisini acik tutar.

Adim 2: DevTools'u Acin

Terminalinizde v tusuna basarak DevTools'u tarayicida acin veya IDE'nizin Flutter panelinden baslayin.

Adim 3: Performans Kaplama Katmani

Once performans kaplama katmanini etkinlestirin. Iki grafik gosterir:

  • UI thread (ust): Widget olusturma ve Dart kodu calistirma suresi
  • Raster thread (alt): GPU'ya birlestirme ve boyama suresi

UI cubugu kirmiziya donerse, Dart kodunuz cok yavas demektir. Raster cubugu kirmiziya donerse, cok fazla katmaniniz veya pahali boyama islemleriniz vardir.

Adim 4: Zaman Cizelgesi Olaylari

Performans sekmesine gecin. Sorunlu bir etkilesimi kaydedin (kaydirma, sayfa gecisi, animasyon). Sonra alev grafikini inceleyin:

  • Uzun build asamalari arayin. Pahali widget agaclarina isaret ederler.
  • Uzun layout asamalari arayin. Karmasik yerlestirme kisitlamalarina veya intrinsic hesaplamalara isaret ederler.
  • paint sivrilmeleri arayin. Eksik repaint sinirlarini gosterirler.

Adim 5: Widget Rebuild Sayaclari

DevTools'ta "Track widget rebuilds" secenegini etkinlestirin. Bu, her widget'in uzerine etkilesiminiz sirasinda kac kez yeniden olusturuldugunu gosteren bir sayac bindirmesi yapar. Statik bir gorunumde birden fazla kez yeniden olusan herhangi bir widget supheli demektir.

Adim 6: Tekrarlayin

En buyuk sorunu duzeltin, yeniden profil cikarin, iyilesmeyi dogrulayin ve tekrarlayin. Her seyi ayni anda duzeltme durtusune karsi koyun. Hedefli, olculmus degisiklikler cok daha etkilidir.

Bellek Sizintisi Tespiti ve Onlenmesi

Flutter'da bellek sizintilari inceliklidir. Cop toplayici cogu seyi halleder, ancak belirli kalipler nesnelerin toplanmasini engeller.

Yaygin Sizinti Kaynaklari

Unutulan dinleyiciler ve abonelikler:

dart
class _MyWidgetState extends State<MyWidget> {
  late StreamSubscription _subscription;

  @override
  void initState() {
    super.initState();
    _subscription = someStream.listen((data) {
      setState(() { /* guncelle */ });
    });
  }

  // Bunu unutursaniz, abonelik bu State nesnesine
  // sonsuza kadar referans tutar
  @override
  void dispose() {
    _subscription.cancel();
    super.dispose();
  }
}

Dispose edilmeyen animasyon controller'lari:

dart
class _AnimatedWidgetState extends State<AnimatedWidget>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 300),
    );
  }

  @override
  void dispose() {
    _controller.dispose(); // Kritik!
    super.dispose();
  }
}

BuildContext yakalayan closure'lar:

dart
// Tehlikeli - closure context'i yakalar, context ise Element agacini tutar
void _onTap(BuildContext context) {
  Future.delayed(Duration(seconds: 5), () {
    // 5 saniye icinde widget dispose edilirse, bu context gecersiz olur
    Navigator.of(context).push(...);
  });
}

// Daha guvenli - mounted kontrolu yapin
void _onTap(BuildContext context) {
  Future.delayed(Duration(seconds: 5), () {
    if (!mounted) return;
    Navigator.of(context).push(...);
  });
}

Bellek Profiler Kullanimi

  1. DevTools'u acin ve Memory sekmesine gidin.
  2. Etkilesimden once bir snapshot alin.
  3. Islemi gerceklestirin (ornegin bir ekrana gidin ve geri donun, 5 kez).
  4. Baska bir snapshot alin.
  5. Buyuyen nesneleri gormek icin diff gorunumunu kullanin. Bir ekrana gidip geri donmek her seferinde yeni nesneler olusturuyor ve eskileri serbest birakmiyorsa, sizinti var demektir.

Ozellikle State nesnelerinin, Stream controller'larinin ve animasyon controller'larinin sayilarindaki buyumeyi arayin.

Gercek Dunya Performans Kazanimlari

Optimize ettigim bir uretim e-ticaret uygulamasinda, urun listeleme ekrani hizli kaydirma sirasinda 20fps'ye dusuyordu. Kok nedenler sunlardi:

  • Her ProductCard, ince bir solma efekti icin bir Opacity sarmalayiciya sahipti ve ekranda 50'den fazla compositing katmani olusturuyordu.
  • Urun gorselleri, 180 piksel genisligindeki kucuk resimler icin tam cozunurlukle (2000 piksel genislik) yukleniyordu.
  • Scaffold seviyesindeki bir BlocBuilder, her sepet guncellemesinde tum sayfayi yeniden olusturuyordu.

Hedefli duzeltmelerden sonra (Opacity'yi onceden hesaplanmis renklerle degistirmek, gorsellere cacheWidth eklemek ve BlocBuilder'i yalnizca sepet ikonu badge'ini saracak sekilde tasimak) kare sureleri 45ms'den 8ms'ye dustu ve bellek kullanimi 120MB azaldi. Tum surec, odakli profilleme ve adim adim degisikliklerle iki gun surdu.

Ileri Teknikler

Karmasik Kaydirma Icin Sliver'lar

Heterojen kaydiriliabilir icerikleriniz oldugunda (basliklar, izgaralar, listeler), ic ice kaydiriliabilir widget'lar yerine CustomScrollView ile sliver'lari kullanin.

dart
CustomScrollView(
  slivers: [
    SliverAppBar(floating: true, title: Text('Urunler')),
    SliverGrid(
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
      ),
      delegate: SliverChildBuilderDelegate(
        (context, i) => ProductCard(products[i]),
        childCount: products.length,
      ),
    ),
  ],
)

setState Yerine ValueListenableBuilder

Ince taneli guncellemeler icin, ValueListenableBuilder yalnizca degere bagli olan alt agaci yeniden olusturur.

dart
final _counter = ValueNotifier<int>(0);

// Sadece bu builder'in alt agaci yeniden olusturulur
ValueListenableBuilder<int>(
  valueListenable: _counter,
  builder: (context, value, child) {
    return Text('Sayac: $value');
  },
)

saveLayer Tetikleyicilerinden Kacinin

Belirli widget'lar dolayli olarak saveLayer cagrisinda bulunur ve ekran disi tampon tahsis eder. En buyuk sorumlular: Opacity, ShaderMask, ColorFiltered, ClipRRect (clipBehavior: Clip.antiAliasWithSaveLayer ile). Bunlari bulmak icin DevTools'taki "highlight saveLayer" gecisini kullanin.

Performans Kontrol Listesi

Her surumden once bu kontrol listesini gecin:

  • [ ] Profile modunda (debug degil) kaydirma performansi profillendi
  • [ ] Normal kullanim sirasinda zaman cizelgesinde 16ms'yi asan kare yok
  • [ ] Tum listeler .builder veya sliver esdeqerlerini kullaniyor
  • [ ] Gorseller cacheWidth/cacheHeight belirtiyor
  • [ ] Mumkun olan her yerde const constructor kullaniliyor
  • [ ] build() metodlarinda agir hesaplama yok
  • [ ] Tum animasyon controller'lari dispose() icinde temizleniyor
  • [ ] Tum stream abonelikleri dispose() icinde iptal ediliyor
  • [ ] Animasyonlu/sik degisen widget'larin etrafina RepaintBoundary eklendi
  • [ ] Buyuk alt agaclari saran gereksiz Opacity widget'lari yok
  • [ ] Bellek snapshot'lari tekrarlanan gezinme sonrasi buyume gostermiyor
  • [ ] Kritik kullanici yollari icin shader isinmasi yapilandirildi
  • [ ] Uygulama boyutu flutter build --analyze-size ile analiz edildi
  • [ ] Release build, en dusuk seviye hedef cihazda test edildi

Sonuc

Performans optimizasyonu tek seferlik bir is degildir. Bir disiplindir. Once olc, en buyuk darbogazy duzelt, iyilesmeyi dogrula ve tekrarla. Araclar mevcut. Kalipler iyi belgelenmis. Akici bir uygulamayi takilanlardan ayiran sey, performansi bir ozellik olarak onceliklendirme kararidir, sonradan eklenen bir dusunce degil.

Flutter uygulamaniz icin uygulamali bir performans denetimi ister misiniz? Darbogazlari birlikte tespit edip cozelim.

İlgili Makaleler

Flutter Projeniz mi Var?

iOS, Android ve web için yüksek performanslı Flutter uygulamaları geliştiriyorum.

İletişime Geç