Laq mobil proqramda istifadəçinin hərəkəti ilə interfeysin reaksiyası arasında nəzərə çarpan gecikmədir və bu, əsas axının həddindən artıq yüklənməsi, yaddaş sızması və ya qeyri-optimal giriş-çıxış əməliyyatları səbəbindən yaranır. Məntiqi səhvlərlə əlaqəli qüsurlardan fərqli olaraq, laq performans problemidir: proqram düzgün, lakin yavaş işləyir. AppDynamics Mobile App Performance Report 2024 məlumatına görə, istifadəçilərin 62%-i proqram 3 saniyədən çox yavaş işləyərsə onu silir. Laqların diaqnozu CPU, yaddaş və şəbəkənin Android Studio Profiler və Xcode Instruments vasitəsilə profilləşdirilməsini tələb edir.
Əsas məqamlar
Laq (ing. lag) mobil proqramda istifadəçinin hərəkəti (toxunma, sürüşdürmə, mətn daxil etmə) ilə interfeysin reaksiyası arasında subyektiv olaraq hiss olunan gecikmədir. Texniki olaraq laq giriş hadisəsi ilə kadrın tam render edilməsi arasındakı vaxt kimi ölçülür: rahat hədd — 100 ms-ə qədər, nəzərə çarpan — 200 ms-dən, kritik — 500 ms-dən çox.
İstifadəçi terminologiyasında „laq edir“ və „yavaşlayır“ tez-tez sinonim kimi istifadə olunur, lakin texniki olaraq laq sabit gecikmədir (məsələn, hər klikdə 300 ms), „yavaşlayır“ isə qeyri-sabit yavaşlamadır: proqram bəzən hamar işləyir, bəzən bir saniyə donur. Qüsur, laqdan fərqli olaraq, sürətlə deyil, göstərmənin düzgünlüyü ilə bağlıdır.
Google Play və App Store proqramların sıralanmasında performans göstəricilərini nəzərə alır. ANR dərəcəsi, jank tezliyi və başlanğıc vaxtı axtarışda görünməyə və quraşdırma konversiyasına təsir edir. Daimi laqları olan proqram ilk işə salındıqdan sonra istifadəçilərin 40%-ə qədərini itirir.
Laqlar əsas UI axını 60 FPS (kadr başına 16.6 ms) və ya 120 FPS (8.3 ms) tezliyi ilə kadrları emal edə bilmədikdə yaranır. Gecikmələrin əsas mənbələrini nəzərdən keçirək.
UI axınında hər hansı sinxron əməliyyat — SharedPreferences-dən oxumaq, suspend olmadan Room vasitəsilə verilənlər bazası ilə işləmək, təsvirin Bitmap-ə dekodlaşdırılması — kadrın çəkilməsini bloklayır. Android-də bu kadrların atlanmasına (jank), iOS-da isə Core Animation renderinin gecikməsinə səbəb olur.
Android-də Garbage Collector və ya iOS-da ARC yaddaşı boşaltdıqda bütün axınlar dayandırılır. Tez-tez GC fasilələri çox sayda müvəqqəti obyekt yaradıldıqda — məsələn, hər dəfə siyahı adapteri çağırıldıqda yeni ViewHolder nümunəsi yaradıldıqda baş verir. Bu özünü sıçrayışlı sürüşdürmə kimi göstərir.
İç-içə ConstraintLayout, çoxsaylı LinearLayout, üst-üstə düşən View — hər iç-içəlik measure və layout pass vaxtını artırır. Xcode göstərir ki, dərin təbəqə iyerarxiyası (10 səviyyədən çox) FPS-in 20-30% düşməsinə səbəb olur.
Laqların səbəblərini aşkar etmək üçün IDE-lərə quraşdırılmış profilerlərdən və sistem monitorinqi alətlərindən istifadə olunur. Hər alət öz vəzifəsini həll edir.
CPU Profiler hansı metodların prosessor vaxtını tutduğunu və hansı axınlarda icra olunduğunu göstərir. Ağır hesablamaları olan metod main thread-də icra olunursa — bu problemin köküdür. Sample Java Method aktivləşdirilmiş izləmə yazısı hər anda çağrı stackini görməyə və „isti nöqtələri“ tapmağa imkan verir.
iOS üçün analoji alət — Time Profiler — hər millisaniyədə stack nümunələri toplayır və hər metodun CPU vaxtının neçə faizini tutduğunu göstərir. Main Thread Only bayrağı ilə kombinasiya yalnız əsas axındakı əməliyyatları filtrləyir ki, bu da birbaşa laq mənbələrini göstərir.
Yavaş şəbəkə sorğuları UI axını bloklanmasa belə laq təəssüratı yaradır. Android Studio-da Network Profiler və Xcode-da Network Link Conditioner yavaş əlaqəni simulyasiya etməyə və proqramın real şəraitdə necə davrandığını müəyyən etməyə imkan verir. Tərəqqisiz chunked cavablar və böyük JSON yükləri — görünən laqların tipik mənbələridir.
Vaxt ölçmə ilə OkHttp vasitəsilə şəbəkə sorğusunun profilləşdirilməsi nümunəsi:
class TimingInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val start = System.nanoTime()
val response = chain.proceed(chain.request())
val duration = (System.nanoTime() - start) / 1_000_000
Log.d("Vaxtlama", "Sorğu $duration ms çəkdi")
return response
}
}
Laqların aradan qaldırılması sistematik iş tələb edir: tək metodun optimallaşdırılmasından memarlıq dəyişikliklərinə qədər. Ən təsirli üsulları nəzərdən keçirək.
Kotlin Coroutines şəbəkə sorğuları üçün Dispatchers.IO dispatcheri və hesablamalar üçün Dispatchers.Default ilə əsas axının UI üçün sərbəst qalmasını təmin edir. iOS-da fon tapşırıqları üçün .global(qos: .userInitiated) növbəsi və UI yeniləməsi üçün .main ilə Grand Central Dispatch standart yanaşmadır. Növbələr arasında sync-əməliyyatlardan çəkinin.
Android-də RecyclerView və iOS-da UICollectionView düzgün konfiqurasiya tələb edir: onBindViewHolder-da minimal obyekt yaradılması ilə ViewHolder, dəyişiklikləri hesablamaq üçün DiffUtil, məlumatları əvvəlcədən yükləmək üçün prefetching. iOS-da əl ilə idarəetmə olmadan animasiya edilmiş yeniləmələr üçün diffable data source istifadə edin.
Hər sürüşdürmədə eyni şəklin yüklənməsi — zəmanətli laqdır. Coil (Android) və Kingfisher (iOS) şəkilləri yaddaşda və diskdə keşləyərək təkrar sorğuda dərhal göstərilməni təmin edir. Məlumatlar üçün Flow və ya Combine əsaslı keşləmə qatı ilə Room istifadə edin.
Android-də Coil ilə şəkil keşləməsinin qurulması nümunəsi:
val imageLoader = ImageLoader(context) {
memoryCachePolicy(CachePolicy.ENABLED)
diskCachePolicy(CachePolicy.ENABLED)
crossfade(true)
size(512, 512)
}
// Avtomatik keşləmə aktivləşdirilmiş yükləmə
imageView.load("https://example.com/image.jpg") {
placeholder(R.drawable.placeholder)
error(R.drawable.error)
}
Laqların qarşısını almaq onları istehsalda düzəltməkdən daha ucuzdur. Profilaktik tədbirlər alətlər və memarlıq səviyyəsində inkişaf prosesinə daxil edilir.
StrictMode — inkişaf mərhələsində əsas axında təsadüfi giriş-çıxış əməliyyatlarını və şəbəkə çağırışlarını aşkar edən quraşdırılmış Android alətidir. Onu Application.onCreate-də kritik pozuntular üçün penaltyDeath siyasəti ilə aktivləşdirin. Bu, proqramçının problemi commitedən əvvəl görməsinə zəmanət verməyin yeganə yoludur.
iOS üçün analoq — Xcode-da Runtime Sanitization-ə daxil olan Main Thread Checker. O, bütün UIKit və AppKit çağırışlarının əsas axından icra olunduğunu avtomatik yoxlayır. Debug qurma sxemində onu aktivləşdirin və CI-da sıfır xəbərdarlığa nail olun.
CI pipeline-na başlanğıc vaxtı, sürüşdürmə FPS və yaddaş istifadəsini ölçmək üçün Macrobenchmark (Android) və XCTMetrics (iOS) icrasını əlavə edin. Həddlər təyin edin: əgər yeni commit başlanğıc vaxtını 5%-dən çox artırarsa — qurma uğursuz olur.
Tez-tez verilən suallar
Laq subyektiv gecikmə hissidir və bu, hətta yüksək FPS-də də yarana bilər, əgər gecikmə render deyil, girişin emal müddəti ilə bağlıdırsa. Aşağı FPS (30 kadr/s-dən az) — laqların səbəblərindən biridir, lakin yeganə deyil.
Android-də Frame Timing API (Choreographer) və iOS-da CADisplayLink istifadə edərək kadrlar arasındakı vaxtı ölçün. Google Play Vitals real şəraitdə jank dərəcəsini göstərir. Dəqiq ölçmələr üçün sürüşdürmə ssenariləri ilə Macrobenchmark tətbiq edin.
Köhnə cihazlar daha az CPU nüvəsinə, daha az RAM-a və daha yavaş yaddaşa malikdir. Flaqmanda 5 ms-də icra olunan əməliyyat büdcə cihazda 50 ms çəkə bilər. Aşağı seqmentli cihazlarda performansı test edin və AOT-kompilyasiya üçün Baseline Profiles təyin edin.
Bəli, bu ən təsirli üsullardan biridir. Yüksək rezolyusiyalı şəkillər çox yaddaş və dekodlaşdırma üçün CPU vaxtı tutur. View ölçüsünə qədər downscale, WebP (Android) və HEIC (iOS) formatları, həmçinin Coil və ya Kingfisher vasitəsilə keşləmədən istifadə edin.
SwiftUI diffing vasitəsilə yeniləmələri avtomatik optimallaşdırır ki, bu da məlumat dəyişikliyi zamanı laq riskini azaldır. Lakin mürəkkəb iyerarxiyalar və tez-tez body yenidənqurmaları FPS düşməsinə səbəb ola bilər. UIKit performans üzərində daha çox nəzarət verir, lakin əl ilə optimallaşdırma tələb edir.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun