Android eğitimi kapsamında App Startup bağımlılık grafiğini Perfetto ve Macrobenchmark ile ölçün; kritik olmayan SDK kurulumlarını ilk karenin dışına taşıyıp cold start regresyonlarını CI içinde yakalayın.
Android Eğitimi: App Startup ile Açılış Bağımlılıklarını Ölçmek
Android eğitimi: Açılış maliyetini tahmin yerine iz ile ölçmek
Bir android eğitimi veya mobil uygulama geliştirme eğitimi projesinde açılış optimizasyonuna başlamadan önce hedef metriği sabitleyin: cold start için process creation ile ilk tam çizim arasındaki süre. Android Studio Profiler'daki CPU görünümü kısa incelemeler için yararlıdır; kök neden analizi için ise sistem scheduler, binder ve frame zaman çizelgesini birlikte gösterdiği için Perfetto kullanın. Ölçümü gerçek cihazda, release'e yakın bir build ile yapın; debug build'deki debugger bağlantısı, doğrulama kontrolleri ve log çağrıları sonucu doğrudan bozar.
# Uygulama verisini ve process'i sıfırlayarak cold start koşulu oluşturun
adb shell am force-stop com.example.app
adb shell pm clear com.example.app
# 15 saniyelik sistem izi alın
adb shell perfetto -o /data/misc/perfetto-traces/startup.perfetto-trace -t 15s sched freq idle am wm gfx view binder_driver hal
adb shell monkey -p com.example.app 1
adb pull /data/misc/perfetto-traces/startup.perfetto-trace ./startup.perfetto-tracePerfetto'da process adınıza göre filtreleyip main thread üzerindeki ilk uzun dilimi bulun. Sık rastlanan hata, yalnızca Activity'nin onCreate() süresine bakmaktır: ContentProvider tabanlı ilkleyiciler Application.onCreate() öncesinde çalışır ve bu maliyet Activity span'ında görünmez. bindApplication, uygulama process'i ve Choreographer#doFrame dilimlerini aynı zaman çizelgesinde karşılaştırın. Değişiklik öncesi ve sonrası için en az 10 cold start çalıştırması alıp medyan ile p95'i ayrı raporlayın; tek bir iyi örnek, CPU frekansı ve termal durum nedeniyle güvenilir değildir.
Jetpack Compose uygulamalarında App Startup bağımlılık grafiği
Jetpack Compose kullanan uygulamada bile açılışın önemli kısmı composable'lar oluşmadan önce çalışır. AndroidX App Startup, manifestte kayıtlı Initializer sınıflarını bir bağımlılık grafiği olarak çözer. Bu nedenle telemetry, remote config, görsel yükleyici veya DI container'ı aynı ilkleyicide toplamak, bağımsız işleri farkında olmadan seri hale getirir. Her ilkleyicinin gerçek bağımlılığını dependencies() içinde tanımlayın; bağımlılığı olmayan işi sırf erişimi kolay olsun diye buraya eklemeyin.
class CrashReporterInitializer : Initializer<CrashReporter> {
override fun create(context: Context): CrashReporter {
return CrashReporter.install(context.applicationContext)
}
override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
}
class AnalyticsInitializer : Initializer<Analytics> {
override fun create(context: Context): Analytics {
val reporter = AppInitializer.getInstance(context)
.initializeComponent(CrashReporterInitializer::class.java)
return Analytics.create(context, reporter)
}
override fun dependencies(): List<Class<out Initializer<*>>> =
listOf(CrashReporterInitializer::class.java)
}Buradaki incelik şudur: AnalyticsInitializer zaten CrashReporterInitializer'a bağlıysa, create() içinde tekrar initializeComponent() çağrısı çoğu durumda mevcut sonucu döndürür; ancak bağımlılığı dependencies() yerine sadece gövde içinde saklamak grafiği görünmez yapar. Test edilebilir ve sıralaması açık bir tasarım için bağımlılığı listede bırakın, create() içinde doğrudan kendi nesnenizi kurun. Manifest kaydı şu şekildedir:
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false">
<meta-data
android:name="com.example.startup.CrashReporterInitializer"
android:value="androidx.startup" />
</provider>Bir bağımlılık kütüphanesi kendi App Startup metadata kaydını getiriyorsa merged manifest'i Android Studio'daki Merged Manifest sekmesinden inceleyin. Kütüphanenin ilkleyicisini kaldırmak için ilgili meta-data öğesine tools:node="remove" uygulayabilirsiniz; fakat bunu yaptıktan sonra ilklemeyi uygulamanın doğru yaşam döngüsü noktasında elle çağırmak zorundasınız. Aksi halde yalnızca açılış süresini değil, örneğin crash raporlama gibi erken olayları da kaybedersiniz.
Kotlin eğitimi: Kritik olmayan SDK kurulumunu ilk çizim sonrasına taşımak
Bir kotlin eğitimi veya kotlin kursu örneğinde en pahalı hata, disk I/O yapan bir SDK'nın Application.onCreate() içinde senkron kurulmasıdır. SharedPreferences migrasyonu, sertifika deposu okuma veya SQLite şema kontrolü main thread'de çalışırsa ilk frame için gereken Looper mesajlarını geciktirir. Önce Perfetto'da bu işin ilk Choreographer#doFrame öncesinde olduğunu doğrulayın; sonra yalnızca ilk ekranda zorunlu olmayan işi ilk başarılı çizimden sonra başlatın.
class MainActivity : ComponentActivity() {
private val applicationScope by lazy {
CoroutineScope(SupervisorJob() + Dispatchers.Default)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
App()
LaunchedEffect(Unit) {
// Composition commit edildikten sonra çalışır.
applicationScope.launch {
analytics.warmUp()
remoteConfig.prefetch()
}
}
}
}
}LaunchedEffect(Unit) ilk composition commit'inden sonra planlanır, fakat bunun ağ isteğinin veya CPU yoğun işin frame bütçesini hiç etkileyemeyeceği anlamına gelmez. warmUp() içinde JSON ayrıştırma ya da bitmap decode varsa işi Dispatchers.Default veya I/O ağırlıklıysa Dispatchers.IO üzerinde yapın; UI state güncellemesini ise küçük ve iptal edilebilir tutun. Ayrıca bu mekanizma process death veya çoklu Activity akışında birden fazla kez çalışabilir. SDK idempotent değilse Mutex ve kalıcı olmayan bir process-seviyesi durum ile tekilleştirin.
İlk ekranda gerçekten gereken bir nesne için erteleme uygulamayın. Örneğin oturum belirtecinden yönlendirme kararı veriliyorsa bu kararın gecikmesi boş ekran veya yanlış route üretir. Bu tür veriyi App Startup'a koymak yerine, küçük bir senkron snapshot okuyup ağ yenilemesini arka plana taşıyın. Bu ayrım, android mvvm mimarisi içinde repository'nin initialRoute() gibi saf ve hızlı bir metot sunmasıyla daha net test edilir.
Android Studio eğitimi: Macrobenchmark ile önce-sonra regresyon kapısı
android studio eğitimi içeriğinde ölçümü tekrarlanabilir hale getirmek için Macrobenchmark modülü ekleyin. App Startup grafiğinden bir SDK'yı erteledikten sonra aynı senaryoda değişiklik öncesi ve sonrası StartupTimingMetric çalıştırın. Hedef, örneğin medyan timeToInitialDisplayMs değerinin düşmesi ve p95'in yükselmemesidir. Ölçüm cihazını USB ile besleyin, animasyonları kapatın ve benchmark öncesinde uygulamayı force-stop edin; aksi halde warm start sonuçları cold start ile karışır.
@RunWith(AndroidJUnit4::class)
class StartupBenchmark {
@get:Rule
val benchmarkRule = MacrobenchmarkRule()
@Test
fun coldStart() = benchmarkRule.measureRepeated(
packageName = "com.example.app",
metrics = listOf(StartupTimingMetric()),
iterations = 15,
startupMode = StartupMode.COLD
) {
pressHome()
startActivityAndWait()
}
}Benchmark çıktısındaki yalnızca ortalama değeri CI eşiği yapmayın. 15 örnekte iki adet 900 ms sıçrama varsa ortalama kabul edilebilir görünürken kullanıcıların bir bölümü belirgin gecikme yaşar. JSON çıktısından p50, p90 ve p95 hesaplayın; örneğin p95 değeri ana dal referansının yüzde 10 üstüne çıkarsa build'i başarısız kılın. Aynı commit için Perfetto trace'i de artifact olarak saklamak, regresyonun bir App Startup ilkleyicisinden mi, binder çağrısından mı yoksa render aşamasından mı kaynaklandığını sonradan doğrulamanızı sağlar.
Android kursu ekiplerinde sürümleme ve Play Store yayınlama kontrolü
Bir android kursu projesinde benchmark sonucunu yalnızca yerelde görmek yeterli değildir. Release varyantına yakın, minify açık bir benchmark APK üretin; R8 bazı sınıfları ve refleksiyon yollarını değiştirebilir. App Startup ile refleksiyon üzerinden bulunan bir sınıf kullanıyorsanız release build'de gerçekten yüklendiğini instrumented test ile doğrulayın. Örnek olarak uygulama açıldıktan sonra AppInitializer.getInstance(context).isEagerlyInitialized(CrashReporterInitializer::class.java) sonucunu assert edin.
Play Store yayınlama öncesinde kapalı test kanalındaki başlangıç metriklerini cihaz sınıfına göre ayırın. Düşük bellekli cihazlarda process'in daha sık öldürülmesi cold start oranını artırır; yalnızca geliştirici cihazındaki warm start sonucu riskleri gizler. Kademeli dağıtımda yeni bir üçüncü taraf SDK eklediyseniz, önce onun initializer metadata kaydını merged manifest'te, sonra Macrobenchmark p95'ini, son olarak da kapalı testteki gerçek açılış dağılımını kontrol eden bir yayın kontrol listesi kullanın.
İlgili Eğitim
YTÜSEM İlgili Eğitim
Sık Sorulan Sorular
Android eğitimi için App Startup mı Application.onCreate mı kullanılmalı?
Zorunlu erken bağımlılıklar için App Startup kullanın; bağımlılık sırasını Initializer.dependencies() ile görünür kılar ve merged manifest üzerinden denetlenebilir yapar. Ancak her SDK'yı buraya koymayın: ilk ekranın ihtiyaç duymadığı telemetry veya prefetch işini ilk çizimden sonraki coroutine'e taşıyın. Kararı Perfetto'da ilk doFrame öncesindeki maliyete ve Macrobenchmark StartupTimingMetric sonucuna göre verin.
Jetpack Compose açılış süresi Macrobenchmark ile nasıl ölçülür?
Benchmark modülünde StartupMode.COLD, en az 15 iteration ve StartupTimingMetric kullanın. Her iteration öncesi pressHome() çağırın; framework cold start koşulunu yönetir. Önceki ve sonraki commit'lerin p50 ile p95 değerlerini aynı fiziksel cihazda karşılaştırın, ardından açıklanamayan fark için Perfetto trace'inde main thread, binder_driver ve gfx track'lerini inceleyin.
Android MVVM mimarisi başlangıçta repository çağrılarını nasıl ayırmalı?
ViewModel'in ilk route kararında sadece yerel, küçük ve senkron bir snapshot kullanın; örneğin token varlığı veya daha önce doğrulanmış kullanıcı kimliği. Ağ yenileme, analytics warm-up ve remote config gibi işlemleri ayrı suspend fonksiyonlara ayırıp UI ilk çizildikten sonra applicationScope içinde başlatın. Repository'nin ana thread'de disk I/O yapmadığını StrictMode diskRead ve Perfetto ile doğrulayın.
Kotlin kursu projesinde App Startup initializer neden release build'de çalışmıyor?
Önce Android Studio Merged Manifest görünümünde initializer için meta-data satırının release varyantında kaldığını kontrol edin. Sonra manifest merger kuralı veya flavor manifestinin bu kaydı tools:node="remove" ile silmediğini doğrulayın. Refleksiyon kullanan SDK'larda R8 kuralı da gerekebilir; fakat geniş keep kuralı eklemeden önce release instrumented testinde AppInitializer.isEagerlyInitialized() ile gerçek davranışı ölçün.
AI / LLM Discovery
Bu makale Opendart Akademi Android 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.


