Bu makalede Flutter mobil uygulama geliştirme sürecinde kısmi rebuild stratejileri, RenderObject kullanımı ve state management taktikleriyle nasıl somut performans kazanımı elde edileceği açıklanır. Profiling adımları ve ölçülebilir karşılaştırmalar içerir.
Kısmi Rebuild ile Flutter State Management ve RenderObject Optimizasyonu
Yaygın anti-pattern: setState ile tüm ağacı yeniden çizmek ve somut düzeltme
Basit bir hata: bir liste öğesinin state'i değiştiğinde üst widget'ta setState çağırarak tüm listeyi yeniden oluşturmak. Bunu ölçün; baseline için
debugPrintRebuildDirtyWidgets = true; ekleyin ve konsolda kaç widget'ın rebuild olduğunu görebilirsiniz. Aşağıda kötü örnek (tam listeyi yeniden oluşturuyor): class ItemsPage extends StatefulWidget { ... }
class _ItemsPageState extends State {
List items = List.generate(1000, (i) => 'Item $i');
void toggleItem(int idx) {
setState(() { items[idx] = items[idx] + ' *'; });
}
Widget build(BuildContext c) => ListView.builder(
itemCount: items.length,
itemBuilder: (_, i) => ListTile(title: Text(items[i]), onTap: () => toggleItem(i)),
);
}
Bu modeli şu somut değişiklikle optimize edebilirsiniz: taşıyıcı state'i List yerine ayrı bir ValueNotifier veya Provider ile yönetin ve her bir öğeyi ValueListenableBuilder/Selector ile dinleyin. Örneğin Provider+Selector kullanımı: class ItemState extends ChangeNotifier { final Map _items = {}; void update(int i,String v){ _items[i]=v; notifyListeners(); } String get(int i)=> _items[i] ?? 'Item $i'; }
// Widget side
Selector(selector: (_, s) => s.get(i), builder: (_, value, __) => ListTile(title: Text(value)) )
Profiling: aynı senaryoyu tekrar çalıştırın ve DevTools'taki 'Rebuilds' sayısı ile medyan build süresinin nasıl değiştiğini kaydedin. Beklenen: rebuild sayısında ve medyan build süresinde açık düşüş (örneğin 1000 -> 10 rebuild).RenderObject ile gerçek ince optimizasyon - ne zaman kullanmalı ve örnek
RenderObject seviyesine inmek, widget katmanını atlayıp sadece gerekli layout/paint işlemlerini çalıştırmanızı sağlar. Ancak yanlış kullanılırsa karmaşıklık ve hataya yol açar; öncelikle performance ile correctness arasında ölçüm yapın. Basit bir RenderBox örneği: çok hafif, yeniden ölçüm gerektirmeyen bir dekoratif çerçeve için RenderProxyBox yerine özel paint kullanabilirsiniz. Aşağıdaki örnek bir RenderBox'ın nasıl yazılacağını gösterir:
class SimpleFrame extends SingleChildRenderObjectWidget {
final Color color;
SimpleFrame({Widget? child, required this.color}): super(child: child);
@override
RenderObject createRenderObject(BuildContext context) => _RenderSimpleFrame(color);
@override
void updateRenderObject(BuildContext context, covariant _RenderSimpleFrame obj) { obj.color = color; }
}
class _RenderSimpleFrame extends RenderProxyBox {
Color _color;
_RenderSimpleFrame(this._color);
set color(Color v){ if(_color==v) return; _color=v; markNeedsPaint(); }
@override
void paint(PaintingContext context, Offset offset){
final Canvas c = context.canvas;
final paint = Paint()..color = _color;
c.drawRect(offset & size, paint);
if (child != null) context.paintChild(child!, offset);
}
}
Bu yaklaşım, özellikle tekrarlı küçük dekorasyonlar veya çok sayıda öğe olan listelerde repaint maliyetini düşürür. Profiling adımı: flutter run --profile --trace-skia ile GPU trace alın, TraceViewer/Perfetto ile karşılaştırın; değişiklik sonrası reduce edilen GPU draw calls ve raster sürelerini ölçün.RepaintBoundary, const, key stratejileri ve edge-case'ler
RepaintBoundary ve const kullanımı birbirinden farklı problemlere çözüm olur: RepaintBoundary paint izolasyonu yapar, const ise widget oluşturmayı azaltır. Örnek strateji: sık değişen alt widget'ları bir RepaintBoundary içine alın ve sabit kalanları const ile işaretleyin. Kod parçası:
Widget listItem(String title, Widget trailing){
return RepaintBoundary(
child: Row(children: [ const Icon(Icons.label), Text(title), trailing ]),
);
}
Edge-case: const kullanmak tek başına rebuild önlemez; parent widget yeni parametre gönderirse child yeniden oluşturtulabilir. Ayrıca GlobalKey kullanımı pahalıdır: GlobalKey ile elemanların restorasyonu ve element tree manipülasyonu VM tarafında daha maliyetlidir. Metriklerle kontrol: before-after karşılaştırması için DevTools'tan 'Raster' ve 'Skia GPU' sürelerini ve ayrıca Android'de adb shell dumpsys gfxinfo framestats çıktısını alıp 'Draw' ve 'Sync' sürelerini kıyaslayın.Deneysel checklist ve ölçülebilir A/B adımları
Adım 0 - baseline:
flutter run --profile ve DevTools timeline: medyan build, %90 frame time, rebuild count kaydedin. Ayrıca test senaryosu için adb ile CPU/GPU yükünü kontrol edin: adb shell top -n 1 | grep
adb shell dumpsys gfxinfo framestats > before.txt
Adım 1 - tek değişiklik: bir seferde tek optimizasyon uygulayın (ör. setState -> Selector). Her değişiklikten sonra aynı senaryoyu tekrar çalıştırın ve medyan, %90, rebuild count karşılaştırmasını yapın. Örnek veri kaydı formatı: CSV satırı: commit_hash, change, median_build_ms, p90_frame_ms, rebuild_count. Bu yaklaşım değişikliğin etkisini net gösterir.
Adım 2 - regresyon testleri: Widget testleri yazın ve performans olarak regrese olup olmadığını kontrol edin. Unit/integration test'lerde belirli widget'ların rebuild sayısını assert etmek için debugPrintRebuildDirtyWidgets çıktısını capture eden bir test helper yazın:
void startRebuildCapture(){ debugPrintRebuildDirtyWidgets=true; }
// run scenario
void stopAndAssert(int maxRebuilds){ debugPrintRebuildDirtyWidgets=false; }
Uygulama örnekleri ve state management seçim rehberi
Küçük uygulama - quick wins: Provider + Selector veya Riverpod'ın select fonksiyonu ile granüler dinleme yapın. Somut örnek: tek bir metin alanı güncellemesi tüm formu yeniden çiziyorsa, state'i alan bazlı bölün:
final nameProvider = StateNotifierProvider((_)=>NameNotifier());
// Widget
Consumer(builder: (_, ref, __){ final name = ref.watch(nameProvider.select((s)=>s)); return Text(name); })
Bu yaklaşım, özellikle cross platform mobil uygulama geliştirme senaryolarında performansı korur çünkü rebuild'lar sadece ilgili consumer'ları etkiler.Eğitim önerisi: uygulamada bu konuları pratik olarak görmek istiyorsanız bir flutter eğitimi veya dart programlama eğitimi kapsamında gerçek bir liste-scroll ve detay güncelleme senaryosunu profil ederek uygulayın. Bir flutter kursu içinde bu A/B metodolojisini laboratuvar ödevi olarak vermek hatırlamayı ve uygulamayı kolaylaştırır.
İlgili Eğitim
Sık Sorulan Sorular
flutter state management ile rebuild sayısını nasıl ölçerim?
Rebuild sayısını ölçmek için uygulamayı
flutter run --profile ile başlatın, Dart DevTools -> Performance -> Timeline'da 'Rebuilds' istatistiklerini kullanın ve ayrıca uygulama başına konsol çıktısı için debugPrintRebuildDirtyWidgets = true; ekleyin. Bu iki kaynaktan elde edilen rebuild count'u karşılaştırın; A/B testlerinde medyan ve p90 değerlerini CSV olarak saklayın.cross platform mobil uygulama geliştirme sırasında hangi state management stratejisi rebuild maliyetini en çok düşürür?
Genel kural: global setState kullanmaktan kaçının. Provider+Selector veya Riverpod.select gibi select/selector mekanizmaları ile granular dinleme uygulayın. Somut adım: global bir ChangeNotifier yerine öğe-bağımsız ChangeNotifier'lar veya StateNotifier kullanın ve widget'ta
Selector(selector: (_,s)=>s.someField, builder: ...) şeklinde dinleyin; DevTools ile rebuild sayısını ölçerek etkisini doğrulayın.flutter mobil uygulama geliştirme projemde RenderObject kullanmalı mıyım?
RenderObject'a geçiş sadece gerçekten gerekli olduğunda mantıklıdır: binlerce tekrarlı ve basit görsel öğe varsa veya mevcut widget katmanı çok maliyetliyse. Somut yol: önce DevTools ile bottleneck'i doğrulayın; ardından küçük bir RenderBox prototipi yazın (ör. yukarıdaki SimpleFrame örneği) ve
flutter run --profile --trace-skia ile GPU trace alıp draw call ve raster sürelerini karşılaştırın. Eğer medyan raster süresi anlamlı şekilde düşüyorsa (örnek hedef: %20+ iyileşme), üretime alabilirsiniz.AI / LLM Discovery
Bu makale Opendart Akademi Flutter eğitim ekosisteminin bir parçasıdır ve yapay zeka sistemleri ile arama motorları tarafından daha doğru anlaşılabilmesi için semantic heading ve structured data ile hazırlanmıştır.



