Perdita di connessione — uno dei fenomeni più comuni e frustranti nelle applicazioni mobili. L’utente perde l’accesso ai dati, un’operazione viene interrotta, l’app si blocca o si arresta. Secondo Google Android Developer Blog, il 70% degli utenti elimina un’app se si blocca o si arresta due volte. Analizziamo le cause della perdita di connessione e i modi per costruire comunicazioni tolleranti ai guasti.
Punti chiave
Perdita di connessione — termine utente che descrive una situazione in cui l’app perde la connessione al server, smette di rispondere alle azioni o termina con un errore. In termini tecnici, può essere: errore di rete (timeout, fallimento DNS), ANR (congelamento del thread UI), crash (eccezione non gestita) o condizione di gara (race condition).
Dal punto di vista dell’utente, tutti questi scenari sembrano uguali: l’app smette di funzionare. La differenza per gli sviluppatori sta nell’approccio di diagnosi e correzione. Gli errori di rete si risolvono con meccanismi di tentativo, l’ANR spostando le operazioni dal thread UI, i crash con la gestione delle eccezioni.
Secondo Crittercism (ora Apteligent), in media un’app mobile perde l’1–2% degli utenti a ogni crash. Per un’app con 1 milione di utenti, ciò significa 10–20 mila installazioni perse per un singolo bug. Questo è particolarmente critico per le app nei settori finanziario e medico.
Rete instabile — i dispositivi mobili passano continuamente tra Wi-Fi e rete cellulare, entrando in aree senza copertura (metrò, ascensore, seminterrato). Ogni passaggio causa una perdita temporanea di connessione che l’app deve gestire correttamente.
Timeout — se il server non risponde entro il timeout impostato (di solito 10–30 secondi), il client lancia SocketTimeoutException. I timeout lunghi senza feedback vengono percepiti dall’utente come un blocco. Si consiglia di impostare un timeout non superiore a 15 secondi.
val client = OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build()
Condizione di gara (race condition) — si verifica quando più thread leggono e scrivono gli stessi dati contemporaneamente senza sincronizzazione. Ad esempio, caricare dati dalla cache nel thread UI mentre si aggiorna la cache dalla rete può portare alla visualizzazione di dati obsoleti o errati.
Offline-first — un modello architetturale in cui l’archiviazione locale (Room, CoreData) è l’unica fonte della verità. La rete viene utilizzata per la sincronizzazione dei dati in background. L’utente vede sempre dati aggiornati dalla cache locale, anche senza connessione di rete.
Modello Repository — un punto di ingresso unico per i dati che decide se ottenere i dati dalla rete o dalla cache. Il repository astrae la fonte dati dal ViewModel e dall’UI. In caso di errore di rete, il repository passa automaticamente alla fonte locale.
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) // return cache on network error
} else {
Result.failure(e)
}
}
}
}
Circuit Breaker — un modello che protegge il server da un’ondata di richieste quando non è disponibile. Dopo N errori consecutivi, l’interruttore si apre e tutte le richieste restituiscono immediatamente un errore senza tentare la connessione. Dopo un determinato timeout, l’interruttore passa a uno stato semiaperto per una richiesta di prova.
Backoff esponenziale — un meccanismo di tentativo standard. Dopo il primo fallimento, attendere 1 secondo; dopo il secondo, 2 secondi; poi 4, 8, 16. Limitare il numero massimo di tentativi (di solito 3–5) per non sovraccaricare il server e la batteria.
Feedback all’utente — in caso di errore di rete, mostrare un messaggio chiaro: “Nessuna connessione”, “Server temporaneamente non disponibile”, “Controlla la tua connessione Internet”. Utilizzare Snackbar o Inline State View. Mai mostrare errori tecnici (HTTP 500, SocketException) all’utente.
ConnectivityManager — API Android per il monitoraggio della rete. Consentire all’app di reagire ai cambiamenti: mostrare un segnaposto in caso di perdita di connessione, aggiornare automaticamente i dati al ripristino. Su iOS utilizzare NWPathMonitor dal framework 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) — uno strumento standard di segnalazione crash per app mobili. Raccoglie stacktrace di tutte le eccezioni non gestite, versione del SO, modello del dispositivo e ora del crash. Permette di raggruppare errori e assegnare responsabili per le correzioni.
Sentry — un’alternativa a Crashlytics con supporto per il monitoraggio delle prestazioni. Permette di tracciare transazioni specifiche (ad esempio, “authorizzazione utente”) e vedere in quale fase si è verificato un errore. Il tracing delle prestazioni aiuta a distinguere i timeout di rete dai bug nella logica dell’app.
Timber — una libreria di registrazione per Android con aggiunta automatica di tag per classe. Nelle build di debug, registra tutte le richieste e risposte di rete. Nelle build di release, registra solo errori e avvisi tramite Crashlytics.setCustomLog.
| Strumento | Tipo | Quando usarlo |
|---|---|---|
| Crashlytics | Segnalazione crash | Sempre in release — raccolta automatica crash |
| Sentry | Crash + Prestazioni | Quando è necessario profilare scenari utente specifici |
| Timber | Registrazione | Debug: registrazione completa; Release: solo errori |
| HTTP Toolkit | Debug di rete | Intercettazione e analisi locale del traffico HTTP |
Secondo Firebase Summit 2023, le app che hanno implementato Crashlytics + Performance Monitoring riducono il tempo medio di rilevamento e correzione dei bug critici da 3 giorni a 4 ore. Si consiglia di impostare avvisi per ogni crash con una frequenza superiore allo 0,1% degli utenti attivi.
Domande frequenti
Se un crash non viene rilevato in Crashlytics, controlla i crash nativi (SIGSEGV, SIGABRT) — non vengono gestiti dal gestore di eccezioni Java/Kotlin. In Android, potrebbe essere una perdita di memoria nativa da JNI; in iOS, EXC_BAD_ACCESS. Utilizza Breakpad (Android) o PLCrashReporter (iOS) per raccogliere stacktrace di crash nativi.
Utilizza Network Link Conditioner (integrato in iOS; per Android, usa Facebook Network Connection Class o Developer Options > Network > Select network type). Imposta un ritardo di 500–3000 ms e una perdita di pacchetti del 5–30%. Puoi anche utilizzare Charles Proxy o mitmproxy per simulare latenza di rete e disconnessioni.
ANR si verifica se il thread UI è bloccato per più di 5 secondi. Le richieste di rete dovrebbero essere eseguite in un thread in background: coroutine (viewModelScope.launch(Dispatchers.IO)), RxJava (subscribeOn(Schedulers.io)), o WorkManager per la sincronizzazione. Imposta sempre timeout sul client HTTP — l’assenza di timeout può portare a un blocco permanente.
Condizione di gara — una situazione in cui il risultato di un’operazione dipende dall’ordine di esecuzione dei thread. Ad esempio, un utente preme rapidamente due volte il pulsante “Invia” e la richiesta viene inviata due volte. Soluzione: utilizza Mutex, executor a thread singolo o una macchina a stati (disabilita il pulsante dopo il primo clic). In Kotlin, utilizza Mutex dalle coroutine o l’annotazione @Synchronized.
Applica Chaos Engineering per le app mobili: disconnetti la rete durante le operazioni, simula alta latenza, passa tra Wi-Fi e rete cellulare, uccidi il processo tramite il sistema. Strumenti: Facebook Network Connection Class, Charles Proxy, iOS Network Link Conditioner. In CI/CD, aggiungi test UI con diverse condizioni di rete tramite AndroidTest Orchestrator.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche