U mobilnom razvoju, rad sa podacima, keširanje i sinhronizacija su tri ključna aspekta koji određuju performanse i pouzdanost aplikacije. Prema Google Android Architecture Guide, pravilna arhitektura obrade podataka direktno utiče na brzinu odgovora i korisničko iskustvo. Repository obrazac obezbeđuje jedinstvenu tačku pristupa svim izvorima podataka.
Ključne Tačke
Repository obrazac je arhitektonski pristup u kojem jedna repozitorijumska klasa upravlja svim operacijama sa podacima, apstrahujući udaljene REST API-je i lokalno skladištenje Room ili SwiftData. Ovakav način rada sa podacima omogućava aplikaciji da prvo dobije informacije iz Memory Cache ili Disk Cache, a zatim iz mreže, smanjujući vreme odgovora. U mobilnom razvoju, Repository je postao de facto standard zahvaljujući preporukama Google-a i Apple-a.
Remote Data Source pruža ažurne informacije sa servera putem HTTP zahteva. Local Data Source je lokalno skladište na uređaju, implementirano kroz Room na Androidu ili SwiftData na iOS-u. Repozitorijum kombinuje oba izvora: prvo proverava lokalni keš, a kada nema podataka, zahteva od udaljenog API-ja. Ovakva organizacija rada sa podacima omogućava aplikaciji da funkcioniše u offline režimu i smanjuje opterećenje servera.
class UserRepository(
private val remoteDataSource: UserRemoteDataSource,
private val localDataSource: UserLocalDataSource
) {
suspend fun getUsers(): List<User> {
localDataSource.getCachedUsers()?.let { return it }
val users = remoteDataSource.fetchUsers()
localDataSource.cacheUsers(users)
return users
}
}
class UserRepository {
private let remote: UserRemoteDataSource
private let local: UserLocalDataSource
func getUsers() async throws -> [User] {
if let cached = await local.getCached() { return cached }
let users = try await remote.fetch()
await local.save(users)
return users
}
}
LRU Cache (Least Recently Used) je algoritam keširanja gde se, kada se dostigne limit, uklanja element kojem se najduže nije pristupalo. U mobilnim aplikacijama, LRU Cache se koristi za slike, API odgovore i serijalizovane objekte. Pravilno keširanje podataka smanjuje broj mrežnih zahteva i ubrzava učitavanje sadržaja. Keš u mobilnim aplikacijama je neophodna komponenta za visoke performanse.
Memory Cache čuva podatke u RAM-u — pristup je izuzetno brz, ali kapacitet je ograničen veličinom heap-a aplikacije. Disk Cache čuva informacije na datotečnom sistemu — sporiji je, ali može da primi više i traje između sesija. Optimalna strategija u mobilnom razvoju je dvoslojni keš: Memory Cache za vruće podatke i Disk Cache za hladne podatke. Prilikom rada sa podacima, prvo se proverava keš prvog nivoa u memoriji, zatim keš drugog nivoa na disku.
class MemoryCache<K, V>(
private val maxSize: Int = 100
) {
private val cache = LinkedHashMap<K, V>(0, 0.75f, true)
fun get(key: K): V? = cache[key]
fun put(key: K, value: V) {
if (cache.size >= maxSize) {
cache.remove(cache.keys.first())
}
cache[key] = value
}
}
TTL keš (Time To Live) automatski uklanja unos nakon određenog vremenskog intervala — pogodno za API podatke. Validacija zasnovana na događajima čisti keš po prijemu push obaveštenja o promenama. U mobilnim aplikacijama, izbor strategije keširanja zavisi od tipa podataka: slike se keširaju dugo, dok novinski feed zahteva čestu validaciju. Coil na Androidu i Kingfisher na iOS-u su već ugradili LRU Cache za rad sa slikama.
Offline Queue je struktura podataka koja čuva korisničke operacije (kreiranje, ažuriranje, brisanje) u lokalnoj bazi podataka kada je uređaj offline. Kada se veza uspostavi, Sync Manager sekvencijalno primenjuje ove operacije na server. Ova vrsta sinhronizacije podataka garantuje da nijedna promena neće biti izgubljena tokom privremenog gubitka mreže. U mobilnom razvoju, Offline Queue je kritična komponenta za aplikacije sa nestabilnom vezom.
Red se gradi na tabeli u Room ili SwiftData sa poljima: tip operacije, JSON telo zahteva, vremenska oznaka i status. Sync Manager je pozadinski servis koji obrađuje operacije na čekanju, šalje ih serveru, ažurira status i uklanja uspešne unose. Sinhronizacija podataka putem WorkManager na Androidu ili BGTaskScheduler na iOS-u nastavlja se čak i nakon ponovnog pokretanja uređaja. Korišćenje Offline Queue zajedno sa pravilnim radom sa podacima obezbeđuje besprekorno korisničko iskustvo.
@Entity
data class SyncOperation(
@PrimaryKey val id: Long,
val endpoint: String,
val method: String,
val body: String,
val createdAt: Long
)
class SyncManager(
private val dao: SyncOperationDao,
private val api: ApiService
) {
suspend fun syncPending() {
dao.getPendingOperations().forEach { op ->
try {
api.execute(op.endpoint, op.method, op.body)
dao.delete(op.id)
} catch (e: Exception) {
// retry on next cycle
}
}
}
}
Eksponencijalno kašnjenje između ponovnih pokušaja (1s, 2s, 4s, 8s) štiti server od naglog opterećenja i sprečava beskonačne pokušaje. Limit od 5 pokušaja sprečava prelivanje reda. Sinhronizacija podataka u mobilnim aplikacijama sa podrškom za idempotentnost na serverskoj strani omogućava bezbedne ponovne pokušaje, izbegavajući duplikate. Ovo je posebno važno za finansijske transakcije i porudžbine.
Conflict Resolution je skup strategija za situacije kada se isti podaci menjaju na različitim uređajima istovremeno. Osnovna sinhronizacija podataka zahteva izbor pristupa: Last-Write-Wins (poslednji zapis pobednik), verzionisanje (viša verzija pobednik) ili ručno rešavanje. U složenim scenarijima koriste se CRDT (Conflict-Free Replicated Data Types) koji garantuju matematičku konvergenciju podataka.
Last-Write-Wins je najjednostavniji za implementaciju, ali može izgubiti korisničke promene. Version Vector — svaki zapis čuva broj verzije i identifikator uređaja; sukob nastaje kada se verzije ne poklapaju. CRDT je najpouzdanija, ali složena strategija: podaci matematički konvergiraju ka jedinstvenom stanju bez centralizovanog koordinatora. Sinhronizacija podataka u mobilnim aplikacijama zasnovana na CRDT-u koristi se u kolaborativnom uređivanju u Google Docs-u i sinhronizaciji beleški u Notion-u.
Kada se aplikacija ažurira, struktura lokalne baze podataka se menja: dodaju se kolone, tabele, indeksi. Schema Migration je proces transformacije postojeće baze u novu šemu bez gubitka podataka. Room podržava migracije kroz klasu Migration sa starom i novom verzijom. SwiftData koristi VersionedSchema za opisivanje promena. Pravilna sinhronizacija podataka između verzija aplikacije zahteva da migracije budu testirane idempotentno.
val migration1to2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE users ADD COLUMN avatar_url TEXT")
}
}
@Database(
entities = [User::class],
version = 2
)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
enum ConflictStrategy {
case lastWriteWins
case versionVector
case crdt
}
struct VersionedDocument {
let id: String
let version: Int
let data: Data
let editedBy: String
func resolve(with remote: VersionedDocument) -> VersionedDocument {
return version >= remote.version ? self : remote
}
}
Room je Google biblioteka za lokalno skladištenje na Androidu, izgrađena na SQLite i pruža anotacije za deklarativni opis upita. SwiftData je Apple frejmvork za iOS, macOS, watchOS i visionOS, naslednik Core Data sa sažetom Swift Macro sintaksom. Oba alata rešavaju zadatak rada sa podacima na uređaju, ali sa različitim pristupima organizaciji koda. Keš u mobilnim aplikacijama se često gradi upravo na ovim tehnologijama.
Room koristi anotacije @Entity za tabele i @Dao za upite. DAO enkapsulira sve SQL operacije sa proverom u vreme kompilacije — SQL sintaksne greške se otkrivaju pre izvršavanja. Type Converter pretvara složene tipove (Date, List) u SQLite primitive. Savremeni rad sa podacima u Android aplikacijama gradi se oko Room + Flow, obezbeđujući reaktivno ažuriranje UI pri promenama u kešu ili lokalnoj bazi.
SwiftData koristi makro @Model za definisanje entiteta i @Query za posmatranje podataka. Frejmvork automatski prati zavisnosti i ažurira interfejs pri promenama. Migracija šeme koristi VersionedSchema koja opisuje sve verzije. Sinhronizacija podataka između SwiftData i servera implementira se kroz prilagođeni Sync Manager koji se pretplaćuje na ažuriranja putem @Query.
@Model
final class UserModel {
var id: String
var name: String
var email: String
var updatedAt: Date
init(id: String, name: String, email: String) {
self.id = id
self.name = name
self.email = email
self.updatedAt = Date()
}
}
| Kriterijum | Room | SwiftData |
|---|---|---|
| Platforma | Android | Apple (iOS, macOS, visionOS) |
| Osnova | SQLite | SQLite (Core Data stek) |
| Sintaksa | Kotlin anotacije | Swift Macro |
| Migracije | Migration klasa | VersionedSchema |
| Reaktivnost | Flow / LiveData | @Query property wrapper |
| Višeplatformski | Samo Android | Samo Apple |
Često postavljana pitanja
LRU Cache je algoritam keširanja koji, kada se dostigne limit, uklanja najmanje skoro korišćeni element. Koristi se za slike i API podatke u mobilnim aplikacijama.
Offline Queue čuva korisničke operacije u lokalnoj bazi podataka kada nema mreže. Sync Manager ih izvršava kada se veza uspostavi, garantujući dostavu promena serveru.
Conflict Resolution je strategija rešavanja sukoba prilikom sinhronizacije podataka. Glavni pristupi: Last-Write-Wins, Version Vector i CRDT za distribuirane sisteme.
Za Android izaberite Room — zrelu biblioteku sa SQL proverom u vreme kompilacije. Za iOS — SwiftData sa deklarativnom sintaksom. Za višeplatformske projekte, SQLDelight ili Realm bi bili odgovarajući.
Optimalna sinhronizacija podataka je pri svakoj promeni za kritične operacije i u pozadini svakih 15–30 minuta za ostale. Koristite push obaveštenja za trenutnu dostavu.
Rezime
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.