Výkon v mobilním vývoji: co to je, jaké metriky a jak zlepšovat

Autor: IT Sectr Publikováno: 2026-03-25 Doba čtení: 12 min

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

  • ANR a Pád — hlavní nepřátelé uživatelského zážitku; předchází se jim vlákny na pozadí
  • Únik paměti a Retain Cycle vedou k pádům OOM; řeší se slabými referencemi a nástroji
  • GC (Android) a ARC (iOS) — modely správy paměti; pochopení jejich fungování je zásadní
  • Profilování (Instruments, Android Profiler, LeakCanary) — povinná fáze vývoje
  • Cold Start — nejdůležitější metrika spouštění; optimalizace Application.onCreate a líná inicializace
  • Velikost aplikace — používat App Bundle, R8, VectorDrawable a WebP pro zmenšení velikosti

Proč aplikace zpomaluje?

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

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.

Správa paměti (GC, ARC, Retain Cycle)

Únik paměti

Ú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ů.

Retain Cycle (Cyklická reference)

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 vs ARC

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:

kotlin
// Утечка: анонимный класс держит ссылку на 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í (Instruments, Android Profiler)

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)iOSCPU, volání funkcí, doba prováděníOptimalizace algoritmů, hledání úzkých míst
Instruments (Allocations)iOSPaměť, počet objektů, retain countsHledání úniků a nadměrné spotřeby paměti
Instruments (Leaks)iOSRetain cycles, úniky pamětiPravidelná kontrola před vydáním
Android Profiler (CPU)AndroidVyužití CPU, aktivita vláken, tracesHledání blokování hlavního vlákna
Android Profiler (Memory)AndroidVýpis haldy, sledování alokacíHledání úniků, analýza objektů
Android Profiler (Network)AndroidProvoz, rychlost, časování požadavkůOptimalizace síťových volání
LeakCanaryAndroidAutomatická detekce úniků pamětiVe všech fázích vývoje
StrictModeAndroidDisk/síť na hlavním vlákně, únikyDebug sestavení
Traceview / SystraceAndroidSledování metod, systémové událostiHloubková 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 (Cold/Warm/Hot Start)

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.

Optimalizace velikosti

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

Co je ANR a jak se mu vyhnout?

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.

Co je únik paměti a Retain Cycle?

Ú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ů.

Jaké nástroje použít pro profilování?

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.

Jak se liší Cold Start od Warm Start a Hot Start?

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.

Jak zmenšit velikost mobilní aplikace?

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í

  • ANR a Pád — hlavní problémy stability; řeší se vlákny na pozadí a hlásiči pádů
  • Únik paměti a Retain Cycle — hlavní příčiny OOM; řeší se slabými referencemi a LeakCanary
  • GC (pauzy Stop-the-World) vs ARC (bez pauz, ale retain cycles) — různé paměťové modely
  • Profilování — povinná fáze: Instruments (iOS), Android Profiler, LeakCanary, StrictMode
  • Cold Start — klíčová metrika; optimalizace Application.onCreate a líná inicializace
  • App Bundle a WebP/VectorDrawable — hlavní nástroje pro zmenšení velikosti o 20-60%
  • Výkon je nepřetržitý proces, ne jednorázová aktivita; integrujte metriky do CI/CD

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í.

Prodiskutovat projekt