Απώλεια σύνδεσης — ένα από τα πιο συνηθισμένα και ενοχλητικά φαινόμενα στις εφαρμογές κινητών. Ο χρήστης χάνει την πρόσβαση σε δεδομένα, η λειτουργία διακόπτεται, η εφαρμογή παγώνει ή κολλάει. Σύμφωνα με το Google Android Developer Blog, το 70% των χρηστών διαγράφει την εφαρμογή αν κολλήσει ή παγώσει δύο φορές. Ας αναλύσουμε τις αιτίες απώλειας σύνδεσης και τους τρόπους δημιουργίας ανθεκτικών επικοινωνιών.
Κύρια σημεία
Αποσυνδέεται — όρος χρήστη που περιγράφει την κατάσταση όταν η εφαρμογή χάνει τη σύνδεση με τον διακομιστή, σταματά να ανταποκρίνεται σε ενέργειες ή τερματίζεται με σφάλμα. Από τεχνική άποψη μπορεί να είναι: σφάλμα δικτύου (timeout, DNS failure), ANR (μπλοκάρισμα νήματος UI), crash (μη διαχειριζόμενη εξαίρεση) ή race condition (συνθήκη ανταγωνισμού).
Για τον χρήστη όλα αυτά τα σενάρια φαίνονται ίδια: η εφαρμογή σταματά να λειτουργεί. Η διαφορά για τον προγραμματιστή βρίσκεται στην προσέγγιση διάγνωσης και επιδιόρθωσης. Τα σφάλματα δικτύου λύνονται με μηχανισμούς retry, το ANR με μεταφορά λειτουργιών εκτός νήματος UI, το crash με διαχείριση εξαιρέσεων.
Σύμφωνα με την Crittercism (τώρα Apteligent), μια μέση εφαρμογή κινητού χάνει 1-2% των χρηστών της σε κάθε κολλάρισμα. Για μια εφαρμογή με 1 εκατομμύριο χρήστες, αυτό σημαίνει 10-20 χιλιάδες χαμένες εγκαταστάσεις ανά σφάλμα. Αυτό είναι ιδιαίτερα κρίσιμο για εφαρμογές στον χρηματοοικονομικό και ιατρικό τομέα.
Ασταθές δίκτυο — οι κινητές συσκευές εναλλάσσονται συνεχώς μεταξύ Wi-Fi και κινητού δικτύου, εισέρχονται σε ζώνες χωρίς κάλυψη (μετρό, ασανσέρ, υπόγειο). Κάθε εναλλαγή προκαλεί προσωρινή απώλεια σύνδεσης που η εφαρμογή πρέπει να χειριστεί σωστά.
Χρονικά όρια — αν ο διακομιστής δεν αποκριθεί εντός του καθορισμένου χρόνου (συνήθως 10-30 δευτερόλεπτα), ο πελάτης εκτοξεύει SocketTimeoutException. Τα μεγάλα χρονικά όρια χωρίς ανάδραση γίνονται αντιληπτά από τον χρήστη ως πάγωμα. Συνιστάται η ρύθμιση χρονικού ορίου όχι μεγαλύτερου από 15 δευτερόλεπτα.
val client = OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build()
Συνθήκη ανταγωνισμού (race condition) — προκύπτει όταν πολλαπλά νήματα διαβάζουν και γράφουν ταυτόχρονα τα ίδια δεδομένα χωρίς συγχρονισμό. Για παράδειγμα, η φόρτωση δεδομένων από την προσωρινή μνήμη στο νήμα UI παράλληλα με την ενημέρωση της προσωρινής μνήμης από το δίκτυο μπορεί να οδηγήσει στην εμφάνιση παλαιών ή εσφαλμένων δεδομένων.
Offline-first — αρχιτεκτονικό μοτίβο όπου η τοπική αποθήκευση (Room, CoreData) είναι η μοναδική πηγή αλήθειας. Το δίκτυο χρησιμοποιείται για συγχρονισμό δεδομένων στο παρασκήνιο. Ο χρήστης βλέπει πάντα ενημερωμένα δεδομένα από την τοπική προσωρινή μνήμη, ακόμα και απουσία δικτύου.
Repository pattern — ενιαίο σημείο εισόδου για δεδομένα που αποφασίζει αν θα λάβει δεδομένα από το δίκτυο ή από την προσωρινή μνήμη. Το αποθετήριο αφαιρεί την πηγή δεδομένων από το ViewModel και το UI. Σε σφάλμα δικτύου, το αποθετήριο μεταβαίνει αυτόματα στην τοπική πηγή.
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) // επιστροφή προσωρινής μνήμης σε σφάλμα δικτύου
} else {
Result.failure(e)
}
}
}
}
Circuit Breaker — μοτίβο προστασίας του διακομιστή από χείμαρρο αιτημάτων όταν είναι μη διαθέσιμος. Μετά από N διαδοχικά σφάλματα, ο διακόπτης ανοίγει και όλα τα αιτήματα επιστρέφουν αμέσως σφάλμα χωρίς προσπάθεια σύνδεσης. Μετά από καθορισμένο χρονικό όριο, ο διακόπτης μεταβαίνει σε μισάνοιχτη κατάσταση για δοκιμαστικό αίτημα.
Exponential backoff — τυπικός μηχανισμός retry. Μετά την πρώτη αποτυχία περιμένετε 1 δευτερόλεπτο, μετά τη δεύτερη — 2 δευτερόλεπτα, στη συνέχεια 4, 8, 16. Περιορίστε τον μέγιστο αριθμό προσπαθειών (συνήθως 3-5) για να μην υπερφορτώνετε τον διακομιστή και την μπαταρία.
Ανάδραση χρήστη — σε σφάλμα δικτύου εμφανίστε ένα κατανοητό μήνυμα: „Δεν υπάρχει σύνδεση”, „Ο διακομιστής είναι προσωρινά μη διαθέσιμος”, „Ελέγξτε το διαδίκτυο”. Χρησιμοποιήστε Snackbar ή Inline State View. Ποτέ μην εμφανίζετε τεχνικά σφάλματα (HTTP 500, SocketException) στον χρήστη.
ConnectivityManager — Android API για παρακολούθηση δικτύου. Επιτρέψτε στην εφαρμογή να αντιδρά σε αλλαγές: σε απώλεια δικτύου εμφανίστε placeholder, σε αποκατάσταση — ενημερώστε αυτόματα τα δεδομένα. Στο iOS χρησιμοποιήστε το NWPathMonitor από το πλαίσιο 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) — τυπικό εργαλείο αναφοράς κολλαρισμάτων για εφαρμογές κινητών. Συλλέγει stacktrace όλων των μη διαχειριζόμενων εξαιρέσεων, έκδοση λειτουργικού συστήματος, μοντέλο συσκευής και χρόνο κολλαρίσματος. Επιτρέπει την ομαδοποίηση σφαλμάτων και την ανάθεση υπευθύνων για διορθώσεις.
Sentry — εναλλακτική του Crashlytics με υποστήριξη παρακολούθησης απόδοσης. Επιτρέπει την ανίχνευση συγκεκριμένων συναλλαγών (π.χ. „ταυτοποίηση χρήστη”) και την προβολή σε ποιο βήμα συνέβη το σφάλμα. Performance tracing βοηθά στη διάκριση χρονικών ορίων δικτύου από σφάλματα στη λογική της εφαρμογής.
Timber — βιβλιοθήκη καταγραφής για Android με αυτόματη προσθήκη ετικετών ανά κλάση. Σε debug build καταγράφετε όλα τα αιτήματα και αποκρίσεις δικτύου. Σε release build — μόνο σφάλματα και προειδοποιήσεις μέσω Crashlytics.setCustomLog.
| Εργαλείο | Τύπος | Πότε να χρησιμοποιείται |
|---|---|---|
| Crashlytics | Crash reporting | Πάντα σε release — αυτόματη συλλογή κολλαρισμάτων |
| Sentry | Crash + Performance | Όταν χρειάζεται προφίλ συγκεκριμένων σεναρίων χρήστη |
| Timber | Logging | Debug: πλήρης καταγραφή; Release: μόνο σφάλματα |
| HTTP Toolkit | Network debug | Τοπική υποκλοπή και ανάλυση κίνησης HTTP |
Σύμφωνα με το Firebase Summit 2023, οι εφαρμογές που εφάρμοσαν Crashlytics + Performance Monitoring μειώνουν τον μέσο χρόνο ανίχνευσης και επιδιόρθωσης κρίσιμων σφαλμάτων από 3 ημέρες σε 4 ώρες. Συνιστάται η ρύθμιση ειδοποιήσεων για κάθε κολλάρισμα με συχνότητα μεγαλύτερη από 0,1% των ενεργών χρηστών.
Συχνές ερωτήσεις
Αν το crash δεν πιάνεται στο Crashlytics, ελέγξτε το native crash (SIGSEGV, SIGABRT) — δεν τα επεξεργάζεται ο χειριστής εξαιρέσεων Java/Kotlin. Στο Android αυτό μπορεί να είναι διαρροή native μνήμης από JNI, στο iOS — EXC_BAD_ACCESS. Χρησιμοποιήστε Breakpad (Android) ή PLCrashReporter (iOS) για συλλογή stacktrace native crash.
Χρησιμοποιήστε Network Link Conditioner (ενσωματωμένο στο iOS, για Android υπάρχει Facebook Network Connection Class ή ρυθμίσεις Developer Options > Network > Select network type). Ρυθμίστε καθυστέρηση 500-3000 ms και απώλεια πακέτων 5-30%. Μπορείτε επίσης να χρησιμοποιήσετε Charles Proxy ή mitmproxy για εξομοίωση καθυστερήσεων δικτύου και αποσυνδέσεων.
ANR προκύπτει όταν το νήμα UI είναι μπλοκαρισμένο για περισσότερο από 5 δευτερόλεπτα. Τα αιτήματα δικτύου πρέπει να εκτελούνται σε νήμα παρασκηνίου: coroutines (viewModelScope.launch(Dispatchers.IO)), RxJava (subscribeOn(Schedulers.io)) ή WorkManager για συγχρονισμό. Πάντα να ορίζετε χρονικά όρια στον πελάτη HTTP — η απουσία χρονικού ορίου μπορεί να οδηγήσει σε αιώνιο μπλοκάρισμα.
Race condition — κατάσταση όπου το αποτέλεσμα μιας λειτουργίας εξαρτάται από τη σειρά εκτέλεσης των νημάτων. Για παράδειγμα, ο χρήστης πατά γρήγορα δύο φορές το κουμπί „Αποστολή” και το αίτημα αποστέλλεται δύο φορές. Λύση: χρησιμοποιήστε Mutex, single-threaded executors ή state machine (απενεργοποιήστε το κουμπί μετά το πρώτο πάτημα). Στο Kotlin χρησιμοποιήστε Mutex από coroutines ή τη σημείωση @Synchronized.
Εφαρμόστε Chaos Engineering για εφαρμογές κινητών: απενεργοποιήστε το δίκτυο κατά τη διάρκεια λειτουργιών, προσομοιώστε υψηλή καθυστέρηση, εναλλάξτε μεταξύ Wi-Fi και κινητού δικτύου, σκοτώστε τη διεργασία από το σύστημα. Εργαλεία: Facebook Network Connection Class, Charles Proxy, iOS Network Link Conditioner. Στο CI/CD προσθέστε δοκιμές UI με διαφορετικές συνθήκες δικτύου μέσω AndroidTest Orchestrator.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης