Pomalá aplikace je hlavní důvod, proč uživatelé odstraňují programy. Milisekundy zpoždění při spuštění nebo posouvání seznamu snižují retenci o desítky procent. Výkon (performance) není jen rychlost, ale také stabilita: absence ANR, pádů a úniků paměti. Tento článek pokrývá všechny aspekty výkonu: od správy paměti (GC, ARC) po profilování pomocí nástrojů. Více v oficiálním průvodci Android Performance.
Hlavní body
Výkon aplikace je přímo spojen s jank — znatelným zpožděním mezi akcí uživatele a reakcí rozhraní. Hlavní příčiny: blokování hlavního vlákna (těžké operace na vláknu UI), časté překreslování rozvržení (overdraw), úniky paměti (častý GC), neoptimální algoritmy (O(n²) na velkých datech). Snímková frekvence (FPS) — počet snímků za sekundu. Pro pohodlný zážitek je potřeba stabilních 60 FPS (Android) nebo 120 FPS (iPhone Pro, iPad Pro). VSync synchronizuje vykreslování s obnovovací frekvencí obrazovky.
Jank nastává, když vykreslení jednoho snímku přesáhne 16,6 ms (pro 60 FPS) nebo 8,3 ms (pro 120 FPS). Profilování GPU (Profile GPU Rendering na Androidu, Core Animation na iOS) ukazuje, které fáze vykreslování zabírají nejvíce času. Hlavní fáze: Layout (umístění prvků), Draw (kreslení), Display (přenos do snímkového bufferu). Nejčastějším problémem je inflace rozvržení v XML, zejména při použití složitých vnořených ConstraintLayout.
Time-to-Interactive (TTI) — čas, za který je aplikace plně připravena k interakci. TTI zahrnuje Cold Start, načítání dat a inicializaci knihoven. Google doporučuje TTI pod 5 sekund, Apple — pod 2 sekundy pro hlavní obrazovky. Líné načítání — technika odloženého načítání obsahu a knihoven, klíčová pro zlepšení TTI. V IT Sectr používáme línou inicializaci ve výchozím nastavení ve všech projektech.
ANR a Pád jsou hlavní nepřátelé výkonu mobilních aplikací. ANR (Application Not Responding) — dialogové okno na Androidu, které se objeví, pokud je hlavní vlákno blokováno déle než 5 sekund. Příčiny: synchronní síťové požadavky na vláknu UI, práce s databází bez korutin, dekódování velkého bitmapu bez downsamplingu, deadlock na hlavním vlákně. Zásobník volání ANR je uložen v /data/anr/traces.txt a umožňuje určit přesné místo blokování.
Pád — neočekávané ukončení aplikace. Na Androidu — Exception (Java/Kotlin) nebo Signal (nativní kód). Na iOS — NSException nebo signál (EXC_BAD_ACCESS — přístup k uvolněné paměti). Nástroje pro hlášení pádů: Firebase Crashlytics, Sentry, BugSnag. Shromažďují stacktrace, data o zařízení a kroky reprodukce. Stack Overflow — přetečení zásobníku volání v důsledku nekonečné rekurze. OutOfMemoryError — když je halda plná.
StrictMode — nástroj Android pro detekci porušení bezpečnosti vláken. Umožňuje nastavit pravidla: ThreadPolicy (zakázat disk/síť na hlavním vlákně), VmPolicy (detekovat úniky Activity, SQLite, CloseGuard). StrictMode by měl být zapnut pouze v debug sestavení — v release by neměl fungovat. Na iOS je ekvivalentem Main Thread Checker (Xcode), který automaticky detekuje volání UIKit mimo hlavní vlákno.
Únik paměti (Memory Leak) — situace, kdy objekt zůstává v paměti, i když jej aplikace již nepoužívá. To přímo snižuje výkon aplikace. Na Androidu GC (Garbage Collection) nemůže objekt shromáždit, pokud na něj existuje silná reference. Typické příčiny: statické reference na Activity, nezrušené callbacky/pozorovatelé, vnitřní třídy s implicitní referencí na vnější třídu, Handler s nevyčištěnými zprávami. LeakCanary — knihovna pro automatickou detekci úniků.
ARC (Automatic Reference Counting) — model správy paměti na iOS. Každý objekt má počítadlo referencí (retain count). Když počítadlo dosáhne nuly, paměť se uvolní. Retain Cycle nastane, když dva objekty drží silné reference na sebe navzájem (A → B a B → A). ARC nikdy nevynuluje počítadla. Řešení: slabé (weak) nebo bezvlastnické (unowned) reference. Weak se automaticky vynuluje (stane se nil) při uvolnění objektu. Unowned se nevynuluje, ale zaručuje, že objekt je živý.
GC (Garbage Collection) pracuje na Androidu (Java/Kotlin). GC pravidelně pozastavuje provádění (pauza Stop-the-World) pro nalezení a uvolnění nedosažitelných objektů. Spouštěč GC: když se halda naplní na určité procento. ARC pracuje na iOS (Swift/Objective-C) a nemá pauzy — počítadla se atomicky aktualizují při každém přiřazení. ARC je předvídatelnější, ale může hromadit nadměrné operace retain/release při vysoké frekvenci přiřazení.
Slabá reference (Weak Reference) a silná reference (Strong Reference) — typ reference určuje, zda GC/ARC může objekt uvolnit. Strong Reference — objekt nebude shromážděn, dokud tato reference existuje. Weak Reference — GC/ARC může objekt shromáždit; slabá reference se stane nil (ve Swift/Java WeakReference). Unowned Reference (Swift) — při uvolnění se nevynuluje; přístup k ní po smrti objektu způsobí pád. Na Androidu se pro slabé reference používá java.lang.ref.WeakReference.
Příklad detekce úniku na Androidu pomocí LeakCanary:
// Утечка: анонимный класс держит ссылку на Activity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
val handler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
// Используем `this@MainActivity`, сохраняя ссылку на Activity
Log.d("TAG", "Handler received message")
}
}
handler.sendEmptyMessageDelayed(0, 60000)
}
}
// Исправление: статический Handler + WeakReference
class SafeHandler(activity: MainActivity) : Handler() {
private val weakActivity =
WeakReference(activity)
override fun handleMessage(msg: Message) {
weakActivity.get() ?: return
Log.d("TAG", "Handler received message")
}
}
Profilování je proces měření výkonu aplikace: CPU, paměť, síť, spotřeba energie. Bez profilování je slepá optimalizace k ničemu — nezjistíte, která část kódu je skutečně pomalá.
| Nástroj | Platforma | Měří | Kdy použít |
|---|---|---|---|
| Instruments (Time Profiler) | iOS | CPU, volání funkcí, doba provádění | Optimalizace algoritmů, hledání úzkých míst |
| Instruments (Allocations) | iOS | Paměť, počet objektů, retain counts | Hledání úniků a nadměrné spotřeby paměti |
| Instruments (Leaks) | iOS | Retain cycles, úniky paměti | Pravidelná kontrola před vydáním |
| Android Profiler (CPU) | Android | Využití CPU, aktivita vláken, traces | Hledání blokování hlavního vlákna |
| Android Profiler (Memory) | Android | Výpis haldy, sledování alokací | Hledání úniků, analýza objektů |
| Android Profiler (Network) | Android | Provoz, rychlost, časování požadavků | Optimalizace síťových volání |
| LeakCanary | Android | Automatická detekce úniků paměti | Ve všech fázích vývoje |
| StrictMode | Android | Disk/síť na hlavním vlákně, úniky | Debug sestavení |
| Traceview / Systrace | Android | Sledování metod, systémové události | Hloubková analýza latence |
Instruments (Xcode) — nejvýkonnější nástroj pro iOS. Time Profiler ukazuje, které funkce spotřebovávají nejvíce CPU. Allocations sleduje vytváření a uvolňování objektů. Leaks automaticky nachází retain cycles. Kroky profilování: (1) spusťte Instruments; (2) vyberte šablonu (Time Profiler pro CPU); (3) spusťte problematický scénář; (4) analyzujte zásobník volání — nejširší sloupec je nejžhavější funkce.
Android Profiler je integrován v Android Studio (View → Tool Windows → Profiler). CPU Profiler ukazuje zatížení každého vlákna. Memory Profiler — výpis haldy a sledování alokací. Network Profiler — všechny HTTP požadavky s časováním. Energy Profiler — spotřeba energie: WakeLock, Location, Network. Pro detailní sledování se používá Systrace (Android 10+) nebo Perfetto — systémové trasování s mikrosekundovou přesností.
Spouštění aplikace je jedním z klíčových ukazatelů výkonu. Dělí se na tři typy: Cold Start — aplikace se spouští od nuly: vytvoří se proces, Application.onCreate (Android) / AppDelegate.applicationDidFinishLaunching (iOS), načtení tříd, inicializace knihoven. Warm Start — proces existuje, ale Activity/ViewController je zničeno (např. při otočení obrazovky nebo návratu z paměti). Hot Start — Activity/ViewController je v paměti, aplikace se jednoduše zobrazí (přepnutí z jiné aplikace).
Cold Start je nejdůležitější metrika. Na Androidu zahrnuje: (1) launch Activity — načtení XML, inicializace View; (2) první snímek — čas do prvního vykreslení. Google doporučuje: launch Activity < 200 ms, první snímek < 500 ms, TTI < 5 sekund. Optimalizace Cold Start: zmenšete Application.onCreate (korutiny pro línou inicializaci), použijte SplashScreen API (Android 12+), odložte inicializaci knihoven (WorkManager, DI), odstraňte zbytečné ContentProviders.
Na iOS Cold Start zahrnuje: načtení binárního souboru Mach-O, dyld (dynamický linker), inicializace běhového prostředí Objective-C, delegát aplikace, první kontroler. Chrome Custom Tabs (Android) a Universal Links (iOS) — technologie pro rychlé otevření externího obsahu v aplikaci bez úplného Cold Start. Doporučuje se testovat Cold Start na skutečných zařízeních střední třídy.
Velikost aplikace je faktorem výkonu pro instalaci a aktualizace. Ovlivňuje konverzi: každých 10 MB snižuje konverzi o 1%. Google Play doporučuje velikost APK pod 150 MB; App Store — pod 200 MB (mobilní sítě — 100 MB). Hlavní metody optimalizace: komprese obrázků (WebP místo PNG šetří 25-35%), vektorizace (VectorDrawable na Androidu, SF Symbols na iOS), odstranění nepoužívaného kódu (R8/ProGuard), odstranění nepoužívaných zdrojů (lint → unused resources).
App Bundle (Android) — formát publikování, při kterém Google Play generuje optimalizované APK pro každé zařízení. App Bundle snižuje velikost stahování o 20-40%. Dynamic Delivery — moduly stahované na vyžádání (on-demand feature modules). Na iOS je ekvivalentem On-Demand Resources (ODR): zdroje stahované po prvním spuštění (herní úrovně, videa).
Líné načítání — technika, při které se moduly a knihovny nenačítají při spuštění, ale načítají se podle potřeby. Split APK (Android) a App Slicing (iOS) — rozdělení aplikace na architektonické sloty: arm64-v8a, x86_64. Optimalizace velikosti aplikace — nepřetržitý proces: analyzujte složení APK (Analyze APK v Android Studio), odstraňte duplicitní ikony, používejte SVG místo několika hustot PNG. V IT Sectr zahrnujeme kontrolu velikosti sestavení do CI/CD pro každý MR.
Často kladené otázky
ANR (Application Not Responding) — dialogové okno na Androidu, které se objeví, pokud je hlavní vlákno blokováno déle než 5 sekund. Abyste se vyhnuli ANR, přesuňte všechny těžké operace (síť, databáze, zpracování souborů) do vláken na pozadí. Ekvivalent na iOS — frozen UI, když aplikace přestane reagovat na dotyky.
Únik paměti — když objekt nelze uvolnit, protože na něj stále existují reference. Retain Cycle — situace v iOS/Objective-C, kdy na sebe dva objekty vzájemně odkazují (A → B → A) a ARC nemůže uvolnit žádný. Řešení: weak/unowned reference a včasné čištění callbacků.
Pro iOS: Instruments (Time Profiler, Allocations, Leaks). Pro Android: Android Profiler (CPU, Memory, Network), LeakCanary (úniky paměti), StrictMode (porušení vláken). Doporučuje se kombinovat profilování během vývoje a integrace.
Cold Start — aplikace se spouští od nuly: proces se vytvoří, třídy se načtou, Application.onCreate se provede. Warm Start — proces existuje, ale Activity/ViewController se znovu vytváří. Hot Start — Activity/ViewController je již v paměti, pouze se zobrazí. Cold Start je nejpomalejší (1-5 sekund) a je kritický pro uživatelský zážitek.
Hlavní metody: odstraňte nepoužívané zdroje a kód (použijte R8/ProGuard), vektorizujte obrázky (VectorDrawable, SF Symbols), komprimujte PNG/WebP (Android), používejte App Bundle místo APK, odstraňte zbytečné knihovny, používejte líné načítání pro moduly. Optimalizace velikosti může zmenšit APK o 40-60%.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.