Pierderea conexiunii — unul dintre cele mai frecvente și enervante fenomene în aplicațiile mobile. Utilizatorul pierde accesul la date, operațiunea este întreruptă, aplicația îngheață sau se blochează. Conform Google Android Developer Blog, 70% dintre utilizatori șterg aplicația dacă aceasta se blochează sau îngheață de două ori. Să analizăm cauzele pierderii conexiunii și metodele de construire a comunicațiilor tolerante la erori.
Principalele puncte
Se deconectează — termen utilizat de utilizatori pentru a descrie situația în care aplicația pierde conexiunea cu serverul, nu mai răspunde la acțiuni sau se termină cu o eroare. În sens tehnic, poate fi: eroare de rețea (timeout, DNS failure), ANR (blocarea firului UI), crash (excepție nehandleată) sau race condition (condiție de cursă).
Pentru utilizator, toate aceste scenarii arată la fel: aplicația încetează să funcționeze. Diferența pentru dezvoltator constă în abordarea diagnosticării și remedierii. Erorile de rețea se rezolvă cu mecanisme de retry, ANR — prin mutarea operațiunilor în afara firului UI, crash — prin gestionarea excepțiilor.
Conform Crittercism (acum Apteligent), o aplicație mobilă medie pierde 1-2% dintre utilizatori la fiecare blocare. Pentru o aplicație cu 1 milion de utilizatori, aceasta înseamnă 10-20 de mii de instalări pierdute pentru o singură eroare. Acest lucru este deosebit de critic pentru aplicațiile din sectorul financiar și medical.
Rețea instabilă — dispozitivele mobile comută constant între Wi-Fi și rețeaua mobilă, intră în zone fără acoperire (metrou, lift, subsol). Fiecare comutare provoacă o pierdere temporară a conexiunii, pe care aplicația trebuie să o gestioneze corect.
Timeouturi — dacă serverul nu răspunde în timpul stabilit (de obicei 10-30 de secunde), clientul aruncă SocketTimeoutException. Timeouturile lungi fără feedback sunt percepute de utilizator ca înghețare. Se recomandă să setați timeoutul la maximum 15 secunde.
val client = OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build()
Condiția de cursă (race condition) — apare atunci când mai multe fire de execuție citesc și scriu simultan aceleași date fără sincronizare. De exemplu, încărcarea datelor din cache în firul UI în paralel cu actualizarea cache-ului din rețea poate duce la afișarea datelor învechite sau incorecte.
Offline-first — model arhitectural în care stocarea locală (Room, CoreData) este singura sursă de adevăr. Rețeaua este utilizată pentru sincronizarea datelor în fundal. Utilizatorul vede întotdeauna date actualizate din cache-ul local, chiar și în absența rețelei.
Repository pattern — punct unic de intrare pentru date care decide dacă să preia datele din rețea sau din cache. Repository-ul abstractizează sursa de date de ViewModel și UI. La eroare de rețea, repository-ul comută automat pe sursa locală.
class UserRepository(
private val api: UserApi,
private val dao: UserDao
) {
suspend fun getUsers(): Result<List<User>> {
return try {
val remote = api.fetchUsers()
dao.insertAll(remote)
Result.success(remote)
} catch (e: IOException) {
val cached = dao.getAll()
if (cached.isNotEmpty()) {
Result.success(cached) // returnează cache-ul la eroare de rețea
} else {
Result.failure(e)
}
}
}
}
Circuit Breaker — model de protecție a serverului împotriva unei avalanșe de cereri când este indisponibil. După N erori consecutive, întrerupătorul se deschide și toate cererile returnează imediat eroare fără încercare de conectare. După un timeout prestabilit, întrerupătorul trece în stare semi-deschisă pentru o cerere de test.
Exponential backoff — mecanism standard de retry. După primul eșec așteptați 1 secundă, după al doilea — 2 secunde, apoi 4, 8, 16. Limitați numărul maxim de încercări (de obicei 3-5) pentru a nu supraîncărca serverul și bateria.
Feedback pentru utilizator — la eroare de rețea afișați un mesaj inteligibil: „Nu există conexiune”, „Serverul este temporar indisponibil”, „Verificați internetul”. Utilizați Snackbar sau Inline State View. Niciodată nu afișați utilizatorului erori tehnice (HTTP 500, SocketException).
ConnectivityManager — API Android pentru monitorizarea rețelei. Permiteți aplicației să reacționeze la schimbări: la pierderea rețelei afișați un placeholder, la restabilire — actualizați automat datele. În iOS utilizați NWPathMonitor din framework-ul Network.
class NetworkMonitor(private val context: Context) {
private val manager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
fun isOnline(): Boolean {
val network = manager.activeNetwork ?: return false
val caps = manager.getNetworkCapabilities(network) ?: return false
return caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
}
}
Crashlytics (Firebase) — instrument standard de raportare a blocărilor pentru aplicații mobile. Colectează stacktrace-ul tuturor excepțiilor nehandleate, versiunea sistemului de operare, modelul dispozitivului și timpul blocării. Permite gruparea erorilor și atribuirea responsabililor pentru remedieri.
Sentry — alternativă la Crashlytics cu suport pentru monitorizarea performanței. Permite trasarea tranzacțiilor specifice (de exemplu, „autentificarea utilizatorului”) și vizualizarea la ce pas a apărut eroarea. Performance tracing ajută la diferențierea timeouturilor de rețea de bug-urile din logica aplicației.
Timber — bibliotecă de logare pentru Android cu adăugare automată de etichete în funcție de clasă. În compilarea debug, logați toate cererile și răspunsurile de rețea. În compilarea release — doar erorile și avertizările prin Crashlytics.setCustomLog.
| Instrument | Tip | Când să utilizați |
|---|---|---|
| Crashlytics | Crash reporting | Întotdeauna în release — colectarea automată a blocărilor |
| Sentry | Crash + Performance | Când trebuie să profilați scenarii specifice de utilizator |
| Timber | Logging | Debug: logare completă; Release: doar erori |
| HTTP Toolkit | Network debug | Interceptarea și analiza locală a traficului HTTP |
Conform Firebase Summit 2023, aplicațiile care au implementat Crashlytics + Performance Monitoring reduc timpul mediu de detectare și remediere a bug-urilor critice de la 3 zile la 4 ore. Se recomandă configurarea alertelor pentru fiecare blocare cu o frecvență mai mare de 0.1% din utilizatorii activi.
Întrebări frecvente
Dacă crash-ul nu este prins în Crashlytics, verificați crash-urile native (SIGSEGV, SIGABRT) — acestea nu sunt gestionate de handler-ul de excepții Java/Kotlin. În Android, aceasta poate fi o scurgere de memorie native din JNI, în iOS — EXC_BAD_ACCESS. Utilizați Breakpad (Android) sau PLCrashReporter (iOS) pentru colectarea stacktrace-ului crash-urilor native.
Utilizați Network Link Conditioner (integrat în iOS, pentru Android există Facebook Network Connection Class sau setările Developer Options > Network > Select network type). Setați întârzierea la 500-3000 ms și pierderea de pachete la 5-30%. De asemenea, puteți utiliza Charles Proxy sau mitmproxy pentru emularea întârzierilor de rețea și a întreruperilor.
ANR apare atunci când firul UI este blocat mai mult de 5 secunde. Cererile de rețea trebuie executate într-un fir de fundal: corutine (viewModelScope.launch(Dispatchers.IO)), RxJava (subscribeOn(Schedulers.io)) sau WorkManager pentru sincronizare. Setați întotdeauna timeouturi pe clientul HTTP — lipsa timeoutului poate duce la blocarea permanentă.
Race condition — situația în care rezultatul unei operațiuni depinde de ordinea executării firelor. De exemplu, utilizatorul apasă rapid butonul „Trimite” de două ori, iar cererea este trimisă de două ori. Soluție: utilizați Mutex, single-threaded executors sau state machine (dezactivați butonul după prima apăsare). În Kotlin, utilizați Mutex din corutine sau adnotarea @Synchronized.
Aplicați Chaos Engineering pentru aplicații mobile: întrerupeți rețeaua în timpul operațiunilor, simulați întârziere mare, comutați între Wi-Fi și rețeaua mobilă, ucideți procesul prin sistem. Instrumente: Facebook Network Connection Class, Charles Proxy, iOS Network Link Conditioner. În CI/CD, adăugați teste UI cu diferite condiții de rețea prin AndroidTest Orchestrator.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și