Vývoj pro Android je jednou z hlavních oblastí softwarového inženýrství, kterým se věnuji.
Nativní Android aplikace vytvářím v Kotlinu, Jetpack Compose a širším ekosystému Android Jetpack s důrazem na čistou architekturu, responzivní uživatelská rozhraní, spolehlivou lokální persistenci, monetizaci, offline chování a dlouhodobou udržovatelnost.
Vývoj pro Android pro mě není jen vytváření obrazovek, které běží v telefonu.
Produkční aplikace musí fungovat napříč různými zařízeními, verzemi Androidu, stavy životního cyklu, síťovými podmínkami a omezenými systémovými prostředky a zároveň zůstat dostatečně srozumitelná, aby ji bylo možné bezpečně rozvíjet i v budoucnu.
Jak k vývoji pro Android přistupuji
Pracuji na Android aplikacích zahrnujících:
- nativní vývoj v Kotlinu,
- rozhraní v Jetpack Compose,
- design v Material 3,
- lokální persistenci,
- integraci REST API,
- offline-first architekturu,
- práci na pozadí,
- billing a monetizaci,
- reklamu,
- lokalizaci,
- widgety,
- nastavení aplikace,
- zpracování médií,
- API zařízení a systému.
Preferuji moderní Android architekturu s explicitním vlastnictvím stavu a jasným oddělením uživatelského rozhraní, aplikační logiky, persistence a externích služeb.
Kotlin
Kotlin je hlavní jazyk, který používám pro vývoj Android aplikací.
Používám jej napříč celým aplikačním stackem:
- stav UI,
- ViewModely,
- repozitáře,
- přístup k databázi,
- síťovou komunikaci,
- billing,
- zpracování na pozadí,
- aplikační logiku.
Null safety, coroutines, Flow a expresivní typový systém Kotlinu přirozeně zapadají do architektury moderních Android aplikací.
Jetpack Compose
Jetpack Compose je hlavní UI toolkit, který používám pro nová Android rozhraní.
Obrazovky vytvářím deklarativně z aplikačního stavu namísto ruční synchronizace hierarchie views.
Typický tok může vypadat takto:
Stav
↓
Jetpack Compose
↓
UI
↓
Akce uživatele
↓
ViewModel
↓
Aktualizovaný stav
Vztah mezi aplikačním stavem a viditelným UI je díky tomu výrazně snazší pochopit.
Material 3
Material 3 používám jako základ mnoha Android rozhraní.
Poskytuje zavedené interakční vzory a komponenty pro:
- navigaci,
- tlačítka,
- karty,
- dialogy,
- typografii,
- plochy,
- theming.
Aplikaci však stále vnímám jako samostatný produkt, nikoli jako pouhé poskládání výchozích Material komponent.
Rozestupy, hierarchie, typografie a návrh interakcí by měly odpovídat účelu konkrétní aplikace.
Android Jetpack
Android Jetpack poskytuje velkou část architektury obklopující aplikaci.
Podle projektu používám například komponenty:
- ViewModel,
- Navigation,
- Room,
- DataStore,
- WorkManager,
- Lifecycle API.
Tyto komponenty poskytují ověřená řešení běžných problémů Android vývoje a snižují potřebu vytvářet vlastní infrastrukturu.
Architektura aplikace
Preferuji jasně oddělené architektonické vrstvy.
Typická aplikace může vypadat například takto:
Jetpack Compose
↓
ViewModel
↓
Repository
↙ ↘
Room REST API
s oddělenou infrastrukturou pro oblasti, jako jsou:
DataStore
Billing
Reklama
Práce na pozadí
Každá vrstva má jasně definovanou odpovědnost.
UI vykresluje stav.
ViewModel koordinuje obrazovku.
Repozitáře poskytují přístup k aplikačním datům.
Persistence a síťová komunikace řeší své vlastní technické oblasti.
Správa stavu
Android aplikace se udržují výrazně snáz, pokud má důležitý stav jasného vlastníka.
Preferuji explicitní modely UI stavu namísto kolekce nesouvisejících mutable proměnných.
Například:
loading
content
error
selectedItem
premiumState
Obrazovka se vykresluje z tohoto stavu.
Chování aplikace se díky tomu snáze kontroluje, ladí a testuje.
ViewModel
ViewModel používám pro stav a logiku, které patří konkrétní obrazovce nebo funkci, ale neměly by záviset na konkrétní instanci Activity nebo composable.
ViewModel může:
- načítat aplikační data,
- zpracovávat akce uživatele,
- komunikovat s repozitáři,
- provádět asynchronní operace,
- zpřístupňovat stav UI.
Composable funkce tak mohou zůstat zaměřené na prezentaci.
Kotlin Coroutines
Většina moderních Android aplikací provádí značné množství asynchronní práce.
Kotlin coroutines používám například pro:
- API požadavky,
- databázové operace,
- zpracování souborů,
- billing,
- výpočty na pozadí.
Náročné operace držím mimo hlavní vlákno, aby uživatelské rozhraní zůstalo responzivní.
Kotlin Flow
Flow používám v případech, kdy se aplikační data v čase mění.
Typické zdroje zahrnují:
- Room,
- DataStore,
- repozitáře,
- aplikační služby.
Běžná architektura může vypadat takto:
Zdroj dat
↓
Flow
↓
ViewModel
↓
Compose
Když se data změní, aktualizovaný stav se může přirozeně propagovat napříč aplikací.
Room
Room používám v případech, kdy aplikace potřebuje strukturovaná relační lokální data.
Může jít například o:
- historii,
- záznamy vytvořené uživatelem,
- cachovaná vzdálená data,
- strukturované kolekce,
- offline obsah.
Room poskytuje entity, DAO, ověřování SQL dotazů, migrace a integraci s Flow a coroutines.
DataStore
DataStore používám pro lehčí persistentní stav, jako jsou:
- preference,
- nastavení,
- stav onboardingu,
- zvolené režimy,
- konfigurace UI.
Rozdíl mezi DataStore a Room držím jasně vymezený.
Preference patří do DataStore.
Větší relační datasety patří do Room.
SQLite
Room používá SQLite jako podkladovou databázi, takže znalost principů relačních databází zůstává důležitá.
Zohledňuji:
- návrh schématu,
- indexy,
- transakce,
- vztahy,
- výkon dotazů.
I lokální mobilní databáze těží z kvalitního datového modelu.
Offline-first návrh
Mobilní připojení není dostatečně spolehlivé na to, aby bylo možné předpokládat, že každá operace vždy dosáhne na server.
Tam, kde je to vhodné, proto navrhuji aplikace primárně kolem lokálního stavu.
Například:
REST API
↓
Repository
↓
Room
↓
Flow
↓
UI
Aplikace tak může zůstat použitelná i offline a synchronizace může lokální databázi aktualizovat ve chvíli, kdy je připojení opět dostupné.
REST API
Android aplikace integruji s REST API například pro:
- vzdálený obsah,
- uživatelské účty,
- synchronizaci,
- aplikační služby,
- externí integrace.
Síťové operace z principu považuji za nespolehlivé.
Aplikace musí počítat s:
- timeouty,
- pomalým připojením,
- offline stavem,
- chybami autentizace,
- poškozenými odpověďmi.
UI by mělo zůstat předvídatelné ve všech těchto situacích.
JSON
JSON se běžně používá pro komunikaci mezi Android aplikacemi a backendovými službami.
Externí data mapuji na typované Kotlin modely namísto předávání volně strukturovaného JSON napříč celou aplikací.
Tam, kde je to vhodné, odděluji:
- API modely,
- databázové entity,
- doménové modely,
- UI modely.
Každá vrstva se tak může vyvíjet nezávisle.
Práce na pozadí
Některé operace by měly pokračovat nebo se opakovat nezávisle na aktuální obrazovce.
Pro tento typ úloh používám odpovídající Android mechanismy pro práci na pozadí, například WorkManager.
Typické úlohy zahrnují:
- synchronizaci,
- uploady,
- periodické zpracování,
- odložené operace.
Rozlišuji mezi persistentní prací na pozadí a běžnými asynchronními UI operacemi.
Coroutine spuštěná z ViewModelu není automaticky náhradou za persistentního workera.
Životní cyklus aplikace
Android aplikace neběží jako jednoduchý nepřerušovaný proces.
Activities mohou být znovu vytvořeny.
Aplikace může přecházet mezi popředím a pozadím.
Operační systém může proces ukončit.
Stav proto navrhuji podle skutečné délky jeho životního cyklu.
Dočasný UI stav může patřit do Compose.
Stav obrazovky může patřit do ViewModelu.
Persistentní data patří do Room nebo DataStore.
Ukončení procesu
ViewModel nenahrazuje persistenci.
Pokud důležitý stav musí přežít ukončení procesu, ukládám jej odpovídajícím způsobem.
Toto rozlišení je důležité pro prevenci aplikací, které při vývoji vypadají správně, ale v reálných mobilních podmínkách ztrácejí kritický stav.
Navigace
Používám strukturovanou navigaci namísto toho, aby jednotlivé obrazovky přímo závisely jedna na druhé.
U Compose aplikací je navigace reprezentována explicitními destinacemi a routami.
Preferuji předávání stabilních identifikátorů mezi destinacemi namísto přenášení velkých aplikačních objektů prostřednictvím navigace.
Cílová obrazovka si může potřebná data načíst z vrstvy aplikačního stavu.
Adaptivní layouty
Android běží napříč:
- telefony,
- tablety,
- skládacími zařízeními,
- různými orientacemi,
- různými velikostmi oken.
Rozhraní nenavrhuji pro jedinou pevnou velikost obrazovky.
Na větších displejích se může přizpůsobit i samotná informační architektura.
Například:
telefon
→ jednopanelové rozhraní
velká obrazovka
→ layout seznam–detail
Responzivní Android design není jen zvětšování stejného telefonního rozhraní.
Přístupnost
Přístupnost je součástí kvality aplikace.
Zohledňuji:
- sémantické popisky,
- velikost dotykových cílů,
- barevný kontrast,
- škálovatelný text,
- chování se screen readery,
- preference omezených animací tam, kde je to vhodné.
Vlastní UI by nemělo ztrácet informace o přístupnosti, které standardní Android komponenty poskytují automaticky.
Škálování písma
Uživatelé mohou systémovou velikost písma výrazně zvětšit.
Rozhraní proto navrhuji tak, aby to zvládlo, místo předpokladu, že každý popisek se vejde do pevně daného obdélníku.
To ovlivňuje:
- výšku komponent,
- zalomení řádků,
- omezení layoutu,
- navigační popisky.
Podpora většího textu zároveň často zlepšuje celkovou robustnost UI.
Tmavý režim
Tam, kde je to vhodné, podporuji světlé i tmavé téma.
Namísto hard-coded barev rozesetých po celé aplikaci používám sémantické barvy tématu.
Vizuální systém se díky tomu snáze udržuje a aplikace se může přizpůsobovat konzistentně.
Lokalizace
Aplikace navrhuji tak, aby byl text oddělený od implementačního kódu a bylo možné jej čistě lokalizovat.
Lokalizace znamená víc než jen překlad řetězců.
Různé jazyky mohou ovlivnit:
- délku textu,
- zalomení řádků,
- šířku tlačítek,
- pravidla množného čísla,
- formát data,
- formát čísel.
Proto se vyhýbám layoutům, které fungují pouze pro jeden jazyk.
Google Play Billing
Google Play Billing integruji v případech, kdy aplikace potřebuje:
- jednorázové nákupy,
- předplatné,
- prémiovou funkcionalitu,
- nákup odstranění reklam.
Nákupy považuji za persistentní oprávnění, nikoli za dočasné události po stisku tlačítka.
Platební logika musí počítat s:
- obnovením nákupů,
- čekajícími nákupy,
- potvrzením nákupu,
- opětovným připojením,
- chybovými stavy.
Google Mobile Ads / AdMob
U bezplatných aplikací financovaných reklamou integruji Google Mobile Ads obezřetně.
Podle aplikace může jít o:
- rewarded reklamy,
- interstitial reklamy,
- app open reklamy,
- bannery.
Reklamní logiku držím oddělenou od jádra aplikace.
Pokud se reklamu nepodaří načíst, běžná funkcionalita aplikace by měla obecně pokračovat bez omezení.
Architektura monetizace
Monetizaci preferuji jako samostatný subsystém.
Například:
Google Play Billing
↓
Stav oprávnění
↓
Funkce aplikace
a:
Stav oprávnění
↓
AdMob
Nákup pro odstranění reklam tak může reklamu deaktivovat, aniž by každá jednotlivá obrazovka musela rozumět celé implementaci billing systému.
Souhlas a soukromí
Reklama a analytika mohou zahrnovat zpracování citlivé z hlediska soukromí.
Aplikace proto navrhuji tak, aby stav souhlasu skutečně ovlivňoval její chování a nebyl pouze vizuálním dialogem.
Pokud SDK vyžaduje oprávnění nebo souhlas, okolní architektura musí tento stav respektovat.
Oprávnění
Android aplikace by měly vyžadovat pouze oprávnění, která skutečně potřebují.
Nevyžaduji široký přístup jen proto, že je technicky dostupný.
Požadavek na oprávnění by měl přijít v kontextu, ve kterém uživatel rozumí tomu, proč jej daná funkce potřebuje.
Aplikace by také měla umět zamítnutí oprávnění korektně zpracovat.
Práce se soubory
Některé Android aplikace potřebují pracovat s lokálními soubory.
Používám moderní Android storage a document API namísto předpokladu neomezeného přístupu k souborovému systému.
Aplikace by měla fungovat v rámci bezpečnostního modelu Androidu a požadovat přístup pouze ke zdrojům, které konkrétní funkce skutečně potřebuje.
Zpracování médií
U aplikací pracujících s obrázky, zvukem nebo videem zohledňuji nejen funkcionalitu, ale také omezené prostředky zařízení.
Zpracování médií může být náročné na:
- CPU,
- paměť,
- úložiště,
- baterii.
Náročné operace neprovádím přímo na UI vlákně a u delších úloh poskytuji jasnou zpětnou vazbu o průběhu.
Widgety
Tam, kde to dává smysl, vytvářím Android widgety na domovskou obrazovku jako rozšíření hlavní aplikace.
Widget má vlastní designová omezení, protože:
- má omezený prostor,
- není běžnou obrazovkou aplikace,
- může se aktualizovat nezávisle,
- musí být užitečný na první pohled.
Widgety vnímám jako lehká rozhraní k aplikačním datům, nikoli jako zmenšené kopie celé aplikace.
Notifikace
Pokud aplikace potřebuje notifikace, navrhuji je kolem skutečné hodnoty pro uživatele.
Notifikace by měly komunikovat užitečný stav nebo časově citlivé informace.
Nevytvářím notifikační chování pouze za účelem zvýšení engagementu.
Uživatelé by měli mít jasnou kontrolu nad tím, jaké druhy notifikací dostávají.
Výkon
Mobilní aplikace fungují pod přísnějšími omezeními prostředků než desktopový software.
Sleduji:
- rychlost spuštění,
- zbytečné recomposition,
- databázové dotazy,
- síťové požadavky,
- načítání obrázků,
- spotřebu paměti,
- zpracování na pozadí.
Výkonové problémy, které jsou na vývojářském zařízení téměř neviditelné, mohou být výrazné na slabších zařízeních.
Správa paměti
Velké obrázky, mediální soubory a kolekce mohou rychle spotřebovat značné množství paměti.
Zpracovatelská workflow navrhuji tak, aby nepředpokládala neomezené prostředky.
Může to zahrnovat:
- inkrementální zpracování,
- odpovídající velikosti obrázků,
- omezení zbytečných kopií bufferů,
- uvolňování prostředků, které již nejsou potřeba.
Spolehlivé chování na reálných zařízeních je důležitější než teoretická maximální kvalita.
Spotřeba baterie
Mobilní software musí zohledňovat také spotřebu energie.
Vyhýbám se zbytečnému:
- pollingu,
- smyčkám na pozadí,
- síťovým požadavkům,
- wakeupům,
- časté práci s polohou nebo senzory.
Chování na pozadí by mělo odpovídat skutečné hodnotě, kterou přináší.
Zpracování chyb
Chyby považuji za běžné stavy aplikace.
Mezi možná selhání patří:
- nedostupná síť,
- selhání databáze,
- neplatná data,
- nedostupný billing,
- zamítnuté oprávnění,
- nepodporovaný soubor,
- selhání úlohy na pozadí.
Aplikace by měla vysvětlit, co se stalo, a nabídnout rozumnou cestu k nápravě namísto prostého pádu.
Defenzivní vývoj
Mobilní aplikace fungují v prostředích, která nemám pod kontrolou.
Uživatelé mohou mít:
- neobvyklé konfigurace zařízení,
- málo volného úložiště,
- přerušované připojení,
- starší verze Androidu,
- chování specifické pro konkrétní výrobce.
Proto preferuji defenzivní aplikační logiku s explicitním zpracováním chybějících zdrojů a neúspěšných operací.
Testování
Důležitou logiku testuji na vrstvě, kde to přináší největší hodnotu.
Může jít například o:
- unit testy,
- testy repozitářů,
- databázové testy,
- testy ViewModelů,
- UI testy.
Zvláštní hodnotu pro mě mají regresní testy pro problémy, které se již v minulosti objevily.
Jakmile je chyba identifikována, test může pomoci zabránit jejímu návratu.
Testování na zařízeních
Emulátor je užitečný, ale nereprezentuje každé reálné zařízení.
Zohledňuji testování napříč:
- různými velikostmi obrazovek,
- verzemi Androidu,
- výkonnostními úrovněmi,
- změnami orientace,
- událostmi životního cyklu.
Aplikace určené pro reálné uživatele musí přežít podmínky mimo ideální vývojové prostředí.
Logování
Kvalitní logování pomáhá diagnostikovat problémy, které nelze okamžitě reprodukovat.
Loguji dostatek informací k pochopení důležitých selhání, aniž bych vystavoval citlivá uživatelská nebo autentizační data.
Produkční diagnostika by měla pomoci odpovědět:
- co selhalo,
- kde,
- v jakém stavu aplikace.
Prevence pádů
Prevence pádů není pouze o blocích try-catch.
Začíná u:
- explicitního stavu,
- null safety,
- validovaných vstupů,
- architektury respektující životní cyklus,
- bezpečné persistence,
- defenzivních externích integrací.
Kvalitní architektura předchází mnoha chybovým stavům ještě předtím, než je potřeba zpracovávat výjimku.
Správa závislostí
Android aplikace často závisejí na velkém množství knihoven.
Závislosti přidávám uvážlivě.
Před přidáním další knihovny zvažuji:
- zda řeší skutečný problém,
- údržbu,
- velikost aplikace,
- kompatibilitu,
- bezpečnost,
- zda danou funkcionalitu již neposkytuje Android nebo Jetpack.
Menší počet závislostí je obecně snazší dlouhodobě udržovat.
Gradle
Gradle je součástí Android build systému, se kterým pracuji pro:
- závislosti,
- build varianty,
- konfiguraci verzí,
- pluginy,
- balíčkování.
Build konfiguraci držím pod správou verzí a zbytečně nespoléhám na nastavení specifická pro konkrétní počítač.
Build by měl být reprodukovatelný i mimo původní vývojové prostředí.
Build varianty
Tam, kde je to vhodné, používám různé build konfigurace pro prostředí, jako jsou:
- vývoj,
- testování,
- produkce.
To může pomoci oddělit:
- API endpointy,
- chování logování,
- testovací reklamní konfiguraci,
- feature flags.
Konfigurace specifická pro konkrétní prostředí by měla být záměrná a neměla by vznikat pomocí ručních úprav zdrojového kódu na poslední chvíli.
Release engineering
Android aplikace není hotová ve chvíli, kdy úspěšně běží v IDE.
Práce na releasu může zahrnovat:
- verzování aplikace,
- podepisování,
- release buildy,
- shrinking a optimalizaci,
- konfiguraci obchodu,
- testování produkčního chování.
Release konfiguraci považuji za součást projektu, nikoli za nesouvisející poslední krok.
Google Play
U aplikací distribuovaných prostřednictvím Google Play zahrnuje vývoj také pochopení publikačního životního cyklu.
Může zahrnovat:
- aplikační bundly,
- release tracky,
- testovací vydání,
- konfiguraci billing systému,
- požadavky obchodu.
Produkční chování je potřeba testovat se stejnou pečlivostí jako vývojové buildy.
Git a GitHub
Android projekty držím pod správou verzí v Gitu.
To zahrnuje:
- zdrojový kód v Kotlinu,
- Compose rozhraní,
- Gradle konfiguraci,
- lokalizaci,
- databázová schémata,
- aplikační resources.
Správu verzí používám jako bezpečnostní vrstvu pro:
- vývoj funkcí,
- refaktoring,
- releases,
- změny kódu s podporou AI.
Důležité změny by měly zůstat dohledatelné a vratné.
Vývoj s podporou AI
Vývoj s podporou AI používám k urychlení Android vývoje tam, kde přináší skutečnou hodnotu.
Může pomoci například s:
- implementací,
- refaktoringem,
- debuggingem,
- návrhem architektury,
- lokalizací,
- testy.
Vygenerovaný kód je stále potřeba kontrolovat a testovat.
Android má mnoho omezení souvisejících s životním cyklem a platformou, která nelze bezpečně ignorovat jen proto, že vygenerovaný kód projde kompilací.
Udržovatelnost
Android projekty navrhuji s předpokladem, že se budou měnit.
Nové funkce mohou přinést:
- další obrazovky,
- nové datové zdroje,
- billing,
- lokalizaci,
- úlohy na pozadí,
- nové požadavky na persistenci.
Jasné hranice mezi komponentami činí tyto změny výrazně bezpečnějšími.
Preferuji architekturu, která může růst postupně, namísto nutnosti přepisovat celou aplikaci při každé významnější nové funkci.
Omezení overengineeringu
Dobrá Android architektura nepotřebuje maximální možný počet vrstev.
Malé utility mohou zůstat malé.
Architektonickou složitost přidávám pouze tehdy, pokud řeší skutečný problém.
Cílem je:
- jasný stav,
- jasné vlastnictví,
- jasný datový tok.
Nikoli architektonický formalismus.
Android Development v mém technologickém stacku
Vývoj pro Android běžně kombinuji s:
- Kotlinem,
- Android Jetpack,
- Jetpack Compose,
- Material 3,
- Room,
- DataStore,
- SQLite,
- Kotlin Coroutines,
- Kotlin Flow,
- REST API,
- JSON,
- Google Play Billing,
- Google Mobile Ads / AdMob,
- Git a GitHub.
Tyto technologie společně poskytují základ pro moderní nativní Android aplikace.
Proč vytvářím nativní Android aplikace
Nativní Android vývoj používám tam, kde aplikace těží z přímé integrace s platformou Android, vysokého výkonu a přístupu k širšímu Android ekosystému.
Kotlin a Jetpack Compose poskytují moderní vývojový model.
Jetpack poskytuje zavedenou architekturu.
Room a DataStore poskytují persistenci.
REST API poskytují konektivitu.
Služby Google Play poskytují infrastrukturu pro distribuci a monetizaci.
Výsledkem není pouze Android rozhraní.
Je to kompletní softwarový systém, který musí zůstat spolehlivý napříč měnícími se zařízeními, sítěmi, stavy životního cyklu a budoucími verzemi aplikace.
Takto k vývoji pro Android přistupuji: jako k dlouhodobému aplikačnímu inženýrství, nikoli pouze jako k vytváření mobilních obrazovek.