Bölüm 10 — Konu 48: DevTools Profiling
Dizi · 48/61 Flutter Türkçe Tutorial
- Bölüm 1 — Konu 1: Flutter Nedir, Mimarisi (Widget → Element → RenderObject, Skia/Impeller)
- Bölüm 1 — Konu 2: Ortam Kurulumu (Flutter SDK, Android Studio/VS Code, Emulator/Simulator, DevTools'a İlk Bakış)
- Bölüm 1 — Konu 3: İlk Proje Yapısı (`pubspec.yaml`, `lib/`, Klasör Mimarisi, `flutter create` Anatomisi)
- Bölüm 1 — Konu 4: Hot Reload / Hot Restart Ne Yapıyor, Neden Önemli
- Bölüm 2 — Konu 5: "Her Şey Widget'tır" Felsefesi, Widget Ağacı
- Bölüm 2 — Konu 6: StatelessWidget vs StatefulWidget + `setState()` Derinlemesine (Rebuild Mekanizması)
- Bölüm 2 — Konu 7: Temel Layout — Container, Row, Column, Stack, Padding, Align, Center
- Bölüm 2 — Konu 8: Constraint Sistemi — "Constraints Go Down, Sizes Go Up, Parent Sets Position"
- Bölüm 2 — Konu 9: `Expanded`, `Flexible`, `Spacer`, Intrinsic Widget'lar
- Bölüm 3 — Konu 10: MaterialApp/CupertinoApp, Scaffold, AppBar
- Bölüm 3 — Konu 11: `ListView`, `GridView`, `SingleChildScrollView` (+ Builder Pattern)
- Bölüm 3 — Konu 12: Text, TextStyle, Icon, Image, Asset Yönetimi
- Bölüm 3 — Konu 13: Custom Widget Yazma Prensipleri (Composition Over Inheritance)
- Bölüm 3 — Konu 14: Navigator 1.0 — Push/Pop, Named Routes
- Bölüm 4 — Konu 15: Form, TextField/TextFormField, GlobalKey<FormState>, Validasyon
- Bölüm 4 — Konu 16: Theme Sistemi (ThemeData, ColorScheme)
- Bölüm 4 — Konu 17: Responsive & Adaptive Tasarım (MediaQuery, LayoutBuilder, OrientationBuilder, Breakpoint Stratejileri)
- Bölüm 5 — Konu 18: Future/Async-Await Flutter Bağlamında, FutureBuilder
- Bölüm 5 — Konu 19: `Stream`, `StreamBuilder`
- Bölüm 5 — Konu 20: HTTP İstekleri (`http` / `dio` Paketleri)
- Bölüm 5 — Konu 21: JSON Serialization (Manuel → `json_serializable`/`freezed`)
- Bölüm 5 — Konu 22: Local Storage — `shared_preferences` → `Hive` → `sqflite`/Drift
- Bölüm 6 — Konu 23: InheritedWidget ve InheritedModel — "Neden setState Yetmiyor" Sorusunun Cevabı
- Bölüm 6 — Konu 24: Provider Paketi
- Bölüm 6 — Konu 25: Riverpod (Modern Yaklaşım, Provider'ın Halefi)
- Bölüm 6 — Konu 26: BLoC/Cubit Pattern (`flutter_bloc`)
- Bölüm 6 — Konu 27: GetX (Tartışmalı Ama Yaygın)
- Bölüm 6 — Konu 28: Karşılaştırma — Hangi Projede Hangisi?
- Bölüm 7 — Konu 29: Navigator 2.0 (Router, RouteInformationParser, RouterDelegate)
- Bölüm 7 — Konu 30: `go_router` Paketi (Pratik ve Modern Çözüm)
- Bölüm 7 — Konu 31: Deep Linking
- Bölüm 7 — Konu 32: Repository Pattern, Katmanlı Mimari (Data/Domain/Presentation)
- Bölüm 7 — Konu 33: Dependency Injection (`get_it`, `injectable`)
- Bölüm 7 — Konu 34: Clean Architecture Uyarlaması, SOLID Prensipleri
- Bölüm 8 — Konu 35: Implicit Animasyonlar
- Bölüm 8 — Konu 36: Explicit Animasyonlar (`AnimationController`, `Tween`, `Curve`)
- Bölüm 8 — Konu 37: Hero Animasyonları
- Bölüm 8 — Konu 38: `CustomPainter` / `Canvas`
- Bölüm 8 — Konu 39: Rive / Lottie Entegrasyonu
- Bölüm 9 — Konu 40: Platform Channels
- Bölüm 9 — Konu 41: Permission Yönetimi (`permission_handler`)
- Bölüm 9 — Konu 42: Kamera, Konum, Sensörler
- Bölüm 9 — Konu 43: Push Notification (Firebase Cloud Messaging)
- Bölüm 9 — Konu 44: Android/iOS Build Sistemleri
- Bölüm 10 — Konu 45: Test Yazımı (Unit, Widget, Integration, Golden)
- Bölüm 10 — Konu 46: CI/CD
- Bölüm 10 — Konu 47: Rebuild Optimizasyonu (`const`, `key` Kullanımı)
- Bölüm 10 — Konu 48: DevTools Profiling
- Bölüm 10 — Konu 49: Lazy Loading, Pagination, Büyük Liste Performansı
- Bölüm 11 — Konu 50: Firebase Ekosistemi (Auth, Firestore, Storage, Functions)
- Bölüm 11 — Konu 51: Supabase Alternatifi
- Bölüm 11 — Konu 52: GraphQL (Opsiyonel)
- Bölüm 11 — Konu 53: Store Yayınlama Süreci (İmzalama, Listing, Versiyonlama)
- Bölüm 11 — Konu 54: App Size, Obfuscation, Flavor Yönetimi
- Bölüm 12 — Konu 55: Flutter Web / Desktop
- Bölüm 12 — Konu 56: Custom `RenderObject` Yazımı
- Bölüm 12 — Konu 57: Engine Mimarisi Derinlemesine (Impeller vs Skia)
- Bölüm 12 — Konu 58: Plugin Geliştirme, pub.dev'e Paket Yayınlama
- Bölüm 12 — Konu 59: Monorepo Mimarisi (Melos)
- Bölüm 12 — Konu 60: Erişilebilirlik (Accessibility) Derinlemesine
- Bölüm 12 — Konu 61: Yerelleştirme (Localization / i18n)
İçindekiler 10 başlık
- DevTools Nedir, Nasıl Açılır?
- Widget Inspector — Ağacı Gözle Görmek
- "Track Widget Rebuilds" — Konu 47'nin Kanıtı
- Performance / Timeline Görünümü — "Jank" Avcılığı
- CPU Profiler — "Hangi Fonksiyon Zaman Yiyor?"
- Memory Görünümü — Bellek Sızıntılarını Yakalamak
- Network Görünümü — HTTP İsteklerini İzleme
- Pratik Bir İş Akışı — "Bir Şey Yavaş" Şikayetiyle Karşılaştığında
- 🎯 Bu Dersten Çıkarılması Gerekenler
- 📝 Ödevler
Konu 47'de const/key ile teorik olarak nasıl optimize edeceğimizi öğrendik — ama "bu optimizasyon gerçekten işe yaradı mı?" sorusunu tahmin ederek değil, ölçerek cevaplamalısın. Bu derste, Flutter'ın hazır profiling aracı DevTools'u öğreneceğiz.
DevTools Nedir, Nasıl Açılır?
flutter run --profile # PROFILE modda çalıştır — Bölüm 9 Konu 44'ü hatırlaUygulamayı --profile modunda çalıştırdığında, terminalde bir DevTools URL'si verilir (ya da IDE'nin Flutter eklentisi, DevTools'u otomatik açar). DevTools, tarayıcıda çalışan bir web arayüzüdür — uygulamanın canlı durumuna bağlanır ve çeşitli sekmeler halinde farklı analiz araçları sunar.
Neden --profile, --debug değil? Bölüm 9 Konu 44'te öğrendiğimiz build türlerini hatırla: debug modu, hot reload'ı mümkün kılan ekstra kod taşır — bu ekstra kod, performans ölçümlerini bozar (gerçekte var olmayan bir yavaşlık gösterir). Profile modu, release'e yakın performans sunar ama profiling araçlarının (DevTools'un bağlanabileceği) çalışmasına izin verir — bu yüzden her zaman --profile ile ölçüm yaparsın, --debug ile asla.
Widget Inspector — Ağacı Gözle Görmek
Bölüm 1'den beri zihninde kurduğun widget ağacı kavramını, Widget Inspector gerçek zamanlı, tıklanabilir bir ağaç olarak gösterir:
- Ekranda bir widget'a tıklayarak, o widget'ın tam olarak hangi Dart koduna karşılık geldiğini bulabilirsin.
- "Layout Explorer", Bölüm 2 Konu 8'de öğrendiğimiz constraint sistemini ("constraints go down, sizes go up") görsel olarak gösterir — bir widget'ın neden o boyutta olduğunu, hangi constraint'i kimden aldığını görebilirsin. Bir
Expanded/Flexible(Bölüm 2 Konu 9) davranışını anlamıyorsan, bu araç en hızlı öğrenme yoludur.
"Track Widget Rebuilds" — Konu 47'nin Kanıtı
DevTools'un Performance sekmesinde, "Track widget rebuilds" seçeneğini açtığında, ekranın üzerine her widget'ın kaç kez yeniden build() edildiğini gösteren sayılar/renkler biner. Bu, Konu 47'de öğrendiğin const/key optimizasyonlarının gerçekten çalışıp çalışmadığını doğrulamanın doğrudan yoludur:
- Bir widget'ı
constyaptın ve rebuild sayısı hâlâ artıyorsa — muhtemelenconstyanlış yere konmuş, ya da o widget'ın bir üst ebeveyni her seferinde yeni bir nesne oluşturuyor (örn.constolmayan bir parametre veriyorsun). - Beklenmedik şekilde çok sık rebuild olan bir widget bulursan — bu, "widget'ı küçük parçalara böl" (Konu 47) tavsiyesinin tam olarak nerede uygulanması gerektiğini gösterir.
Performance / Timeline Görünümü — "Jank" Avcılığı
Hedef: 60 FPS (saniyede 60 kare) = her kare için ~16.6 milisaniye bütçe
120Hz ekranlarda: her kare için ~8.3 milisaniye bütçeFlutter, akıcı bir deneyim için her "kare"yi (frame) belirli bir süre içinde çizmek zorundadır. Bir kare bu süreyi aşarsa, kullanıcı bunu "jank" (kasma, takılma) olarak hisseder. Timeline görünümü, her kareyi bir çubuk olarak gösterir — çubuk kırmızıysa, o kare bütçeyi aşmıştır.
Bir kare neden yavaş olur? İki ana kategori:
- UI thread'de yavaşlık — genelde çok karmaşık/derin bir widget ağacının
build()'i, ya da Bölüm 8 Konu 38'de öğrendiğimizCustomPainter'ınpaint()metodunda pahalı bir hesaplama. - Raster thread'de yavaşlık — widget ağacı hazır ama gerçek çizim (Skia/Impeller'ın pikselleri boyaması) yavaş; genelde çok fazla katman/efekt (gölgeler, saydamlıklar,
ClipPath) üst üste bindiğinde görülür.
DevTools, hangi kare hangi thread'de ne kadar zaman harcadığını ayrı ayrı gösterir — bu ayrım, nereye odaklanman gerektiğini belirler (kod mu optimize edilmeli, yoksa görsel efektler mi sadeleştirilmeli).
CPU Profiler — "Hangi Fonksiyon Zaman Yiyor?"
main()
└─ build() — %45
└─ pahaliHesaplama() — %38 ← İŞTE SORUN BURADA
└─ diğer — %55CPU Profiler, bir kayıt süresi boyunca hangi fonksiyonun toplam sürenin ne kadarını tükettiğini, çağrı zincirleriyle birlikte (bir "flame chart" olarak) gösterir. Bölüm 8 Konu 38'de shouldRepaint'i her zaman true döndürmenin neden kötü olduğunu tartışmıştık — CPU Profiler, tam olarak böyle bir hatayı, "bu fonksiyon beklenmedik kadar sık çağrılıyor" şeklinde somut bir kanıtla ortaya çıkarır.
Memory Görünümü — Bellek Sızıntılarını Yakalamak
Bölüm 8 Konu 36'da AnimationController.dispose()'u unutmanın bir bellek sızıntısına yol açtığını, Bölüm 9 Konu 42'de bir StreamSubscription.cancel()'ı unutmanın aynı sınıf hata olduğunu öğrenmiştik — Memory görünümü, bu tür sızıntıları somut olarak görmeni sağlar:
- Bir ekrana gir-çık yapıp, bellek kullanımının başlangıç seviyesine dönüp dönmediğini gözlemlersin. Sürekli yükselen bir çizgi (her gir-çıkta biraz daha fazla bellek kullanımı), bir sızıntının işaretidir.
- "Garbage Collector'ı zorla çalıştır" butonu, Dart Bölüm 13'te öğrendiğimiz memory model/GC konusunu hatırlarsan, kullanılmayan nesnelerin gerçekten temizlenip temizlenmediğini doğrulamana yardımcı olur — GC çalıştıktan sonra bile bellek düşmüyorsa, bir yerlerde hâlâ referans tutulduğu (örn.
dispose()edilmemiş bir controller) anlamına gelir.
Network Görünümü — HTTP İsteklerini İzleme
Bölüm 5 Konu 20'de öğrendiğimiz http/dio çağrılarının tümünü, DevTools'un Network sekmesinde gerçek zamanlı izleyebilirsin — hangi endpoint'e, ne zaman, ne kadar sürede istek atıldığını, dönen JSON'u (Bölüm 5 Konu 21) doğrudan görebilirsin. Bu, "API'den yanlış veri geliyor" gibi sorunları, print() satırları eklemeden doğrudan teşhis etmeni sağlar.
Pratik Bir İş Akışı — "Bir Şey Yavaş" Şikayetiyle Karşılaştığında
--profilemodunda çalıştır, sorunun olduğu ekrana git.- Timeline'da kayıt başlat, sorunlu etkileşimi (örn. bir listeyi kaydır) yap, kaydı durdur.
- Kırmızı kareleri bul — UI thread mi, raster thread mi yavaş?
- UI thread yavaşsa → "Track widget rebuilds" ile hangi widget'ın gereksiz yeniden çizildiğine bak (Konu 47'deki
const/keyçözümleri burada devreye girer). - Raster thread yavaşsa → görsel efektleri (gölgeler,
ClipPath, saydamlık katmanları) sadeleştirmeyi düşün (Konu 49'da, büyük listeler bağlamında bunu daha fazla göreceğiz). - Şüpheli bir fonksiyon varsa → CPU Profiler ile o fonksiyonun gerçekten zaman yiyip yemediğini doğrula.
🎯 Bu Dersten Çıkarılması Gerekenler
- Performans ölçümü her zaman
--profilemodunda yapılır —--debugmodu, hot reload yükü nedeniyle yanıltıcı sonuçlar verir. - Widget Inspector + Layout Explorer, widget ağacını ve constraint akışını görsel olarak anlamanı sağlar.
- "Track widget rebuilds", Konu 47'deki
const/keyoptimizasyonlarının gerçekten işe yarayıp yaramadığını doğrudan doğrular. - Timeline görünümü, hangi karelerin 16.6ms bütçesini aştığını (jank) ve bunun UI thread mi raster thread mi kaynaklı olduğunu ayırt eder.
- CPU Profiler, hangi fonksiyonun zamanı gerçekten tükettiğini bir flame chart ile gösterir.
- Memory görünümü, Konu 36/42'de öğrendiğimiz
dispose()/cancel()ihmallerinin yol açtığı bellek sızıntılarını somut olarak ortaya çıkarır.
📝 Ödevler
- [ ] Bir uygulamayı
--profilemodunda çalıştır, DevTools'u aç, Widget Inspector ile bir ekrandaki widget ağacını keşfet, Layout Explorer ile birRow/Column'ın constraint akışını incele. - [ ] Konu 47'deki ödevlerden birinde yaptığın
constoptimizasyonunu, "Track widget rebuilds" ile doğrula — rebuild sayısının gerçekten azaldığını göster. - [ ] Bilerek bir
AnimationController.dispose()çağrısını kaldır, Memory görünümünde ekrana gir-çık yaparak bellek kullanımının yükseldiğini gözlemle, sonradispose()'u geri ekleyip düzeldiğini doğrula. - [ ] Bir ekranda ağır bir işlem (örn. büyük bir listeyi sıralama) çalıştır, CPU Profiler ile bu işlemin flame chart'ta ne kadar yer kapladığını incele.
- [ ] Kendi cümlelerinle, "UI thread'deki bir yavaşlıkla raster thread'deki bir yavaşlığın çözümünün neden farklı olduğunu" açıkla.
Sıradaki konu: Bölüm 10 — Konu 49: Lazy Loading, Pagination, Büyük Liste Performansı (RepaintBoundary vb.) — Bölüm 10'un Son Konusu