Flutter mobil uygulama geliştirme projelerinde takılan karelerin UI, raster veya senkron iş yükünden kaynaklandığını DevTools zaman çizelgesiyle ayırın; ölçülebilir düzeltmeler ve regresyon kontrolleri uygulayın.
Flutter Mobil Uygulama Geliştirmede DevTools ile Jank Kök Neden Analizi
Flutter mobil uygulama geliştirmede ölçülebilir jank başlangıç noktası
Jank incelemesini debug modunda yapmayın. Debug moddaki assert kontrolleri, JIT derleme davranışı ve debug servis ek yükü zaman çizelgesini üretim davranışından uzaklaştırır. Hedef cihazda profil derlemesiyle aynı kullanıcı akışını en az 5 kez çalıştırın:
flutter run --profile -d <device-id>
flutter pub global run devtools DevTools Performance ekranında her tur için frame sayısını, 16.67 ms üzerindeki UI ve raster frame sayısını kaydedin. 120 Hz ekranlarda bütçe 8.33 ms olduğu için cihaz yenileme hızını da rapora ekleyin; yalnızca ortalama frame süresi, kısa ancak kullanıcı tarafından hissedilen sıçramaları gizler.Bir flutter eğitimi veya flutter kursu içeriğinde sık görülen hata, kırmızı frame'i doğrudan widget ağacına bağlamaktır. DevTools Frame Chart'ta UI thread uzun ise Dart kodu, build, layout veya senkron veri dönüşümü şüphelidir; raster thread uzun ise resim çözme, clipping, saveLayer veya GPU kompozisyonu incelenmelidir. Önce-sonra kıyasını aynı fiziksel cihaz, aynı veri hacmi, temizlenmiş uygulama durumu ve aynı kaydırma mesafesiyle yapın. Örneğin başlangıç ölçümünüz 300 frame içinde 27 raster frame'in 16.67 ms'yi geçmesi ise, değişiklikten sonra hedefi 3'ün altına indirmek olarak tanımlayın; 'daha akıcı hissettiriyor' kabul kriteri değildir.
Pahalı olduğunu düşündüğünüz senkron bloğu Timeline'a ad vererek Frame Chart'ta doğrudan kanıt üretin. `Timeline.timeSync` yalnızca senkron işi çevrelemelidir; ağ isteğini veya `await` içeren uzun bir akışı bununla etiketlemek, gerçekte boşta geçen süreyi de iş süresi gibi gösterir.
import 'dart:developer' as developer;
List<Product> parseVisibleProducts(List<Map<String, dynamic>> raw) {
return developer.Timeline.timeSync(
'catalog.parseVisibleProducts',
() => raw.map(Product.fromJson).toList(growable: false),
);
} Kayıttan sonra Timeline Events içinde `catalog.parseVisibleProducts` aratın. Etiket 6-10 ms sürüyor ve aynı frame'de build de çalışıyorsa, sorun varsayım değil ölçülmüş bir UI thread darboğazıdır.Flutter state management akışında frame başına olay birleştirme
flutter state management katmanında jank'in tipik nedeni tek bir büyük rebuild değil, bir frame içinde art arda gelen çok sayıda durum yayınıdır. WebSocket'ten 200 fiyat güncellemesi geldiğinde her olayda `notifyListeners`, `emit` veya provider state ataması yapmak, framework'ün build işlemlerini frame sınırına sıkıştırır. DevTools Timeline'da aynı vsync aralığında tekrarlanan `BuildOwner.buildScope` blokları görürseniz, olayları domain seviyesinde bir frame'e birleştirin.
Aşağıdaki örnek, güncellemeleri kaybetmeden son değeri tutar ve bildirimi bir sonraki frame'e erteler. `scheduleFrameCallback` yerine mikro görev kullanmak doğru değildir; mikro görevler event loop'a dönmeden ardışık biçimde çalışarak yine aynı frame bütçesini tüketebilir.
class PriceStore extends ChangeNotifier {
final Map<String, double> _prices = {};
bool _notificationScheduled = false;
UnmodifiableMapView<String, double> get prices =>
UnmodifiableMapView(_prices);
void onPrice(PriceUpdate event) {
_prices[event.symbol] = event.value;
if (_notificationScheduled) return;
_notificationScheduled = true;
SchedulerBinding.instance.scheduleFrameCallback((_) {
_notificationScheduled = false;
notifyListeners();
});
}
} Bu yaklaşım fiyat tick'lerinin ara değerlerini UI'a çizmez, ancak store son değeri korur. Ara değerlerin hukuki veya analitik olarak gösterilmesi gerekiyorsa bu optimizasyon uygulanmamalı; bunun yerine ayrı bir örnekleme politikası tanımlanmalıdır.Değişiklikten önce DevTools'ta 10 saniyelik yoğun veri akışında `notifyListeners` çağrı sayısını Timeline etiketi veya sayaçla kaydedin. Sonra aynı yükte bildirim sayısının ekran yenileme hızını aşmadığını doğrulayın. Bu, cross platform mobil uygulama geliştirme için ayrıca önemlidir: Android ve iOS cihazların yenileme hızı farklı olsa bile yayın frekansını sabit 60 Hz'e kilitlemek yerine frame scheduler'a bırakmak, uygulamanın cihazın gerçek vsync ritmine uyum sağlamasını sağlar.
Raster thread darboğazları: clip, opacity ve katman maliyeti
Raster thread uzunsa DevTools Performance ekranındaki raster frame'i seçin ve Layer Tree ile eşleştirin. Özellikle `Clip.antiAliasWithSaveLayer`, blur efektleri ve üst üste yarı saydam katmanlar ara yüzey oluşturabilir. Bu ara yüzey GPU belleğinde çizilir, sonra ana hedefe kompoze edilir; tam ekran bir katmanda bu işlem kaydırma sırasında her frame tekrarlandığında pahalı hale gelir. Debug görünümünde Repaint Rainbow ve Checkerboard Offscreen Layers seçeneklerini yalnızca aday bölgeleri bulmak için kullanın, son kararı profil modundaki frame süreleriyle verin.
Aşağıdaki değişiklikte amaç, kartın yuvarlatılmış köşeleri için zorla saveLayer oluşturan clip modunu daha ucuz anti-alias clipping ile değiştirmektir. Önce DevTools'ta aynı liste kaydırmasında raster p95 süresini ölçün, sonra değişiklik sonrası p95'i kıyaslayın.
// Kaçının: her kartta ara katman zorlayabilir.
ClipRRect(
borderRadius: BorderRadius.circular(16),
clipBehavior: Clip.antiAliasWithSaveLayer,
child: image,
)
// Doğrulayarak tercih edin: çoğu basit içerikte saveLayer gerekmez.
ClipRRect(
borderRadius: BorderRadius.circular(16),
clipBehavior: Clip.antiAlias,
child: image,
) Bu değişiklik körlemesine uygulanmamalıdır. Çocukta opacity, shader veya blend mode varsa görsel sonuç değişebilir. Altın görüntü testi ile kenar piksellerini kontrol edin ve gerçek hedef GPU'da ölçüm alın.Her animasyonlu alt ağaca `RepaintBoundary` eklemek de otomatik çözüm değildir. Boundary, tekrar kullanılabilir bir raster cache fırsatı yaratabilir; ancak sık değişen içerikte cache her frame geçersizleşir ve fazladan layer kompozisyon maliyeti doğurur. Flutter DevTools'ta ilgili alanın repaint sınırını doğruladıktan sonra sadece statik, pahalı çizilen bir alt ağacı ayırın. Örneğin canlı fiyat metni ile sabit ürün illüstrasyonunu aynı boundary içinde tutmak, metin değiştiğinde illüstrasyonun da yeniden rasterize edilmesine neden olur.
Dart programlama eğitimi perspektifiyle senkron iş yükünü sınırlama
dart programlama eğitimi sırasında çoğu zaman gözden kaçan ayrıntı, küçük görünen JSON dönüşümlerinin liste büyüdükçe UI thread'de doğrusal maliyet yaratmasıdır. Bir arama sonucunda yalnızca ilk 20 öğe görünüyorsa, 2.000 kaydı ekranda kullanılmayan nesnelere dönüştürmeyin. Ağ katmanından gelen ham veriyi sayfalayın veya görünür aralık kadar dönüştürün; bunu `Timeline.timeSync` ile önce ve sonra ölçün. `List.map(...).toList()` çağrısı tek başına zararsız görünse de iç içe model dönüşümleri, tarih parse işlemleri ve kopyalanan koleksiyonlar birleştiğinde frame bütçesini aşabilir.
Aşağıdaki kod, görünür aralık dışındaki öğeleri hemen domain modeline çevirmeyi engeller. Buradaki sınır, UI katmanındaki viewport bilgisine göre belirlenmelidir; rastgele seçilmiş sabit bir sayı olmamalıdır.
List<Product> decodePage(
List<Map<String, dynamic>> response,
int offset,
int limit,
) {
final end = math.min(offset + limit, response.length);
return developer.Timeline.timeSync('catalog.decodePage', () {
return [
for (var i = offset; i < end; i++) Product.fromJson(response[i]),
];
});
} Bu tekniğin edge case'i sıralama ve filtrelemedir: filtre tüm koleksiyonu gerektiriyorsa yalnızca UI tarafında lazy decode yapmak yanlış sonuç üretir. Bu durumda filtreyi sunucuya taşıyın veya indekslenmiş yerel bir veri katmanı kullanın.Profil sonucunu Flutter performans regresyon testine dönüştürme
Manuel DevTools kaydı keşif için yeterlidir, ancak düzeltmenin sonraki sürümde bozulmadığını göstermez. Uygulama içine yalnızca profil veya test derlemelerinde etkinleşen bir `FrameTiming` toplayıcısı ekleyin. `FrameTiming.buildDuration` UI thread, `rasterDuration` ise raster maliyetini ayrı tuttuğu için tek bir toplam süreye göre daha teşhis edilebilir veri üretir.
class FrameBudgetProbe {
final List<FrameTiming> _samples = [];
void start() {
SchedulerBinding.instance.addTimingsCallback(_samples.addAll);
}
Duration p95Raster() {
final values = _samples
.map((t) => t.rasterDuration.inMicroseconds)
.toList()..sort();
final index = ((values.length - 1) * 0.95).round();
return Duration(microseconds: values[index]);
}
} En az 100 frame toplamadan p95 hesaplamayın; 10 frame'lik örneklemde tek bir garbage collection veya sistem kesintisi sonucu yanıltır.CI senaryosunda sabit test verisi, sabit kaydırma mesafesi ve mümkünse ayrılmış fiziksel cihaz kullanın. Emülatör GPU sürücüsü ile gerçek cihazın raster davranışı farklı olabilir. Örnek kabul kuralı: katalog kaydırma akışında p95 `buildDuration` 10 ms, p95 `rasterDuration` 12 ms altında kalmalı ve 16.67 ms'yi aşan frame oranı yüzde 1'i geçmemelidir. Eşikler cihaz sınıfına göre ayrı tutulmalıdır; üst seviye cihazın referansını düşük seviye cihaz için CI kapısı yapmak, gerçek regresyonları gizler.
İlgili Eğitim
YTÜSEM İlgili Eğitim
Sık Sorulan Sorular
Flutter mobil uygulama geliştirmede UI jank mi raster jank mi nasıl ayırt edilir?
Uygulamayı `flutter run --profile` ile fiziksel cihazda çalıştırın ve DevTools Performance kaydında takılan frame'i seçin. UI süresi uzunsa build, layout, senkron parse veya state yayınına bakın; raster süresi uzunsa Layer Tree, offscreen layer checkerboard ve resim çözme maliyetini inceleyin. İkisini tek bir toplam frame süresi olarak değerlendirmeyin.
Flutter state management ile çok sık gelen WebSocket güncellemeleri nasıl işlenmeli?
Her mesajda bildirim yayınlamak yerine son değeri store içinde biriktirin ve `SchedulerBinding.instance.scheduleFrameCallback` ile frame başına en fazla bir bildirim gönderin. Bu model ara UI değerlerini atlar; her değerin görünmesi gerekiyorsa mesajları kaybetmeden ayrı bir zaman serisi saklayın ve çizim için örnekleme kuralı belirleyin.
Flutter eğitimi için performans ölçümünde debug mod neden güvenilir değildir?
Debug mod assert, debug servisleri ve JIT çalışma özellikleri nedeniyle UI thread sürelerini değiştirir. Ölçümü profil modunda, hedef cihaza yakın veriyle yapın. Önce aynı akışta p95 build ve raster sürelerini kaydedin, ardından tek değişiklik uygulayıp aynı cihaz ve veriyle tekrar ölçün.
Cross platform mobil uygulama geliştirme projelerinde aynı frame bütçesi her cihazda geçerli mi?
Hayır. 60 Hz ekranda frame bütçesi yaklaşık 16.67 ms, 120 Hz ekranda yaklaşık 8.33 ms'dir. CI raporunda cihaz modeli ve yenileme hızını saklayın; frame başına state yayını için sabit zamanlayıcı yerine Flutter'ın frame scheduler'ını kullanın.
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.



