Flutter mobil uygulama geliştirme projelerinde açılış gecikmesini ilk raster, etkileşime hazır ekran ve cold start metrikleriyle ayırın; DevTools, Timeline ve platform benchmark’larıyla darboğazı ölçüp doğrulayın.
Flutter Mobil Uygulama Geliştirmede Başlangıç Süresi Analizi
Flutter mobil uygulama geliştirmede açılış hedefini doğru tanımlayın
Açılış süresini tek bir sayı olarak raporlamayın. En az üç işaret noktası üretin: process start → first frame, process start → first frame rasterized ve process start → kullanıcının ilk anlamlı veriyi gördüğü an. İlk frame, framework’ün frame’i planladığını; rasterized frame ise GPU tarafında görüntünün gerçekten üretildiğini gösterir. Oturum bilgisini bekleyen boş bir iskelet ekranı ilk raster hedefini iyileştirirken, kullanıcının iş yapabildiği zamanı iyileştirmeyebilir.
Profile derlemesinde başlangıç izini almak için flutter run --profile --trace-startup komutunu kullanın ve DevTools Performance görünümünde UI, Raster ve async event şeritlerini inceleyin. Aynı akışı en az 10 cold start ile çalıştırın; tek bir iyi sonucu değil p50 ve p90 değerlerini karşılaştırın. Android’de her turdan önce adb shell am force-stop paket.adiniz ile süreci sonlandırmak, bellekte kalmış VM ve disk önbelleği etkisini azaltır.
import 'dart:async';
import 'dart:developer';
import 'package:flutter/widgets.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
final watch = Stopwatch()..start();
final startupTask = TimelineTask()..start('app_start');
runApp(const App());
unawaited(
WidgetsBinding.instance.waitUntilFirstFrameRasterized.then((_) {
startupTask.finish(arguments: {
'first_raster_ms': watch.elapsedMilliseconds,
});
}),
);
}Bu event’i yalnızca profile veya test build’lerinde etkinleştirin; üretim analitiğine her açılışta yüksek ayrıntılı Timeline verisi göndermek gereksiz maliyet yaratır. Kritik incelik şudur: addPostFrameCallback, ilk frame çizilmeden çağrılır; görsel olarak tamamlanmış açılışı ölçmek için waitUntilFirstFrameRasterized kullanın.
Kritik yolu daraltın: runApp öncesi bağımlılık zincirini ayırın
Yaygın hata, runApp öncesinde token okuma, uzaktan konfigürasyon, SQLite migration ve SDK başlatmayı art arda await etmektir. Bu işlemler Dart isolate’ında tamamlanana kadar widget ağacı oluşmaz; dolayısıyla native splash ekranda kalır. İlk frame için zorunlu olan tek bağımlılık genellikle bağlama ve senkron, küçük bir yerel karar verisidir. Ağ tabanlı konfigürasyon veya analitik SDK’ları ilk görünür ekran sonrasına taşıyın.
class Bootstrap extends StatefulWidget {
const Bootstrap({super.key});
@override
State<Bootstrap> createState() => _BootstrapState();
}
class _BootstrapState extends State<Bootstrap> {
Session? _session;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
_hydrateSession();
});
}
Future<void> _hydrateSession() async {
final task = TimelineTask()..start('session_hydration');
try {
final session = await sessionRepository.readCachedSession();
if (!mounted) return;
setState(() => _session = session);
} finally {
task.finish();
}
}
@override
Widget build(BuildContext context) {
return AppShell(session: _session);
}
}Bu düzenleme, migration gibi veri bütünlüğü zorunluluklarını rastgele ertelemek anlamına gelmez. Örneğin şema migration’ı olmadan okunamayan bir oturum tablonuz varsa, migration kritik yoldadır ve süresini ayrı Timeline event’i olarak ölçmelisiniz. Buna karşılık remote config’in yanıtını beklemek çoğu uygulamada kritik yol değildir: zaman aşımında varsayılan davranış zaten tanımlı olmalıdır. Önceki ve sonraki ölçümde app_start ile session_hydration event’lerinin sürelerini ayrı karşılaştırın; yalnızca toplam süreye bakmak hangi await zincirinin taşındığını gizler.
İlk ekranın asset ve font maliyetini DevTools ile bulun
İlk route’ta büyük PNG, çok sayıda SVG veya geniş karakter setli font kullanımı, asset okuma ve image decode işlerini ilk etkileşimle yarıştırabilir. Paket boyutu için flutter build apk --analyze-size çalıştırın; ardından DevTools Performance’da ilk frame çevresindeki ImageDecode, raster ve uzun UI event’lerini eşleştirin. APK boyutunun küçük olması ilk ekranın ucuz olduğu anlamına gelmez: 3 MB’lık tek görselin decode edilmiş RGBA yüzeyi yaklaşık 12 MB bellek kaplayabilir.
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override
void didChangeDependencies() {
super.didChangeDependencies();
WidgetsBinding.instance.addPostFrameCallback((_) {
precacheImage(
const AssetImage('assets/images/product_placeholder.webp'),
context,
);
});
}
@override
Widget build(BuildContext context) => const ProductList();
}Buradaki precacheImage çağrısını ilk frame’den önce yapmayın: decode işi UI/raster yüküyle çakışabilir. Sadece kullanıcı ilk etkileşiminden hemen sonra görülecek 1-2 görseli önbelleğe alın ve DevTools’ta önce-sonra raster sürelerini kontrol edin. Bir başka edge case: yüksek çözünürlüklü tek asset’i her yoğunlukta aynı dosya olarak paketlemek yerine Flutter’ın çözünürlük varyantlarını (2.0x/, 3.0x/) kullanın; aksi halde düşük yoğunluklu cihaz da büyük bitmap decode eder.
Flutter state management başlangıçta gereksiz rebuild üretmesin
Açılışta hydration tamamlanınca tüm uygulama kökünü tek bir durum nesnesine bağlamak, oturum veya feature flag değişiminde yüzlerce widget’ın build edilmesine neden olur. flutter state management katmanında seçili (projected) değer dinlemek bu yayılımı sınırlar. Örneğin flutter_bloc içindeki BlocSelector, yalnızca seçicinin döndürdüğü değer değiştiğinde builder’ı çağırır.
BlocSelector<SessionCubit, SessionState, bool>(
selector: (state) => state.isAuthenticated,
builder: (context, isAuthenticated) {
return isAuthenticated
? const AuthenticatedHome()
: const SignInOrLoadingScreen();
},
)Önce DevTools Inspector’daki Track widget rebuilds seçeneğini açın ve hydration öncesi/sonrası rebuild sayılarını kaydedin. Ardından kökteki geniş BlocBuilder kullanımını selector ile değiştirip aynı cold-start senaryosunu tekrarlayın. Seçicinin döndürdüğü nesne mutable ise bu optimizasyon sessizce bozulur: eşitlik kontrolü eski ve yeni referansı aynı gördüğü için UI güncellenmeyebilir. Bu nedenle seçiciden bool, enum, immutable record veya değer eşitliği tanımlı immutable model döndürün.
Bir flutter eğitimi, flutter kursu veya dart programlama eğitimi sırasında sık atlanan nokta, asenkron hydration’ın sadece I/O problemi olmadığıdır: tamamlanma anındaki state yayılımı da ilk etkileşim süresini etkiler. Bu nedenle repository çağrısının süresini Timeline’da, rebuild yayılımını ise DevTools Inspector’da ayrı ölçün.
Cross platform mobil uygulama geliştirme için cihaz düzeyinde doğrulama
Flutter DevTools Dart ve framework katmanını açıklar; Android ve iOS süreç başlatma maliyetini karşılaştırmak için platform testleri ekleyin. AndroidX Macrobenchmark içindeki StartupTimingMetric, uygulamayı gerçek cihaza yakın koşullarda tekrar tekrar başlatıp cold-start dağılımı üretir. Aşağıdaki testte uygulama paketi benchmark testinin hedefi olmalıdır; debug APK yerine benchmark’ın beklediği profileable/release benzeri yapılandırmayı kullanın.
@RunWith(AndroidJUnit4::class)
class StartupBenchmark {
@get:Rule
val benchmarkRule = MacrobenchmarkRule()
@Test
fun coldStartup() = benchmarkRule.measureRepeated(
packageName = "com.example.app",
metrics = listOf(StartupTimingMetric()),
iterations = 10,
startupMode = StartupMode.COLD
) {
pressHome()
startActivityAndWait()
}
}iOS tarafında aynı sözleşmeyi XCTest ile XCTApplicationLaunchMetric() kullanarak ölçün; ayrıca Instruments App Launch şablonunda main-thread bloklarını inceleyin. Kod değişikliğinden önce ve sonra aynı fiziksel cihazda, aynı uygulama verisi koşulunda p50/p90 cold start sonuçlarını saklayın. Android’de dex/AOT yükleme, iOS’ta dyld ve framework yükleme davranışları farklıdır; bu nedenle cross platform mobil uygulama geliştirme hedefi tek bir milisaniye eşiği değil, her platformda ölçülmüş ve gerilemeye karşı CI’da izlenen bir dağılım olmalıdır.
İlgili Eğitim
YTÜSEM İlgili Eğitim
Sık Sorulan Sorular
Flutter mobil uygulama geliştirmede first frame ile first rasterized frame arasındaki fark nedir?
First frame, framework’ün çizim işini planladığını ifade eder; GPU’ya gönderilmiş görüntünün tamamlandığını garanti etmez. Profile modda WidgetsBinding.instance.waitUntilFirstFrameRasterized ile ikinci işaret noktasını alın ve DevTools Performance’da UI/Raster şeritleriyle karşılaştırın.
Flutter state management açılışta neden gereksiz rebuild oluşturur?
Hydration sonucu kökte dinlenen geniş bir state nesnesi değişirse tüm bağımlı builder’lar tekrar çalışır. BlocSelector, Riverpod select veya benzeri projection API’leriyle yalnızca isAuthenticated gibi immutable bir alanı dinleyin; DevTools Inspector’daki Track widget rebuilds ile değişiklik öncesi ve sonrası sayıları kaydedin.
Flutter eğitimi veya flutter kursu projelerinde cold start nasıl ölçülmeli?
Emülatörün tek seferlik sonucuna güvenmeyin. flutter run --profile --trace-startup ile framework event’lerini, Android’de Macrobenchmark StartupTimingMetric ile en az 10 cold start’ı ölçün. Sonuçları ortalama yerine p50 ve p90 olarak raporlayın; bu yaklaşım dart programlama eğitimi içindeki async bootstrap değişikliklerinin etkisini görünür yapar.
Cross platform mobil uygulama geliştirmede remote config runApp öncesinde beklenmeli mi?
Yalnızca uygulamanın güvenli varsayılan ekranı remote config olmadan belirlenemiyorsa beklenmelidir. Çoğu durumda yerel varsayılanı kullanıp config isteğini ilk frame sonrası başlatmak daha doğrudur. Kararı varsayım ile değil, Timeline’da remote config await süresi ve Macrobenchmark cold-start p90 sonucu ile doğrulayı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.



