Odpada — co to jest, typowe przyczyny i metody rozwiązania

Autor: IT Sectr Opublikowano: 2026-07-29 Czas czytania: 10 min

Utrata połączenia — jedno z najczęstszych i najbardziej irytujących zjawisk w aplikacjach mobilnych. Użytkownik traci dostęp do danych, operacja zostaje przerwana, aplikacja zawiesza się lub ulega awarii. Według Google Android Developer Blog, 70% użytkowników usuwa aplikację, jeśli ulegnie ona awarii lub zawiesi się dwukrotnie. Omówimy przyczyny utraty połączenia oraz sposoby budowania niezawodnej komunikacji.

Najważniejsze

  • ANR (Application Not Responding) — blokada wątku UI dłuższa niż 5 sekund prowadzi do wymuszonego zakończenia
  • Offline-first — architektura, w której lokalne przechowywanie jest źródłem prawdy, a sieć mechanizmem synchronizacji
  • Retry with backoff — automatyczne ponowienie żądania z rosnącym opóźnieniem przy błędach sieciowych
  • ConnectivityManager — Android API do śledzenia stanu sieci i dostosowywania zachowania aplikacji
  • Graceful degradation — aplikacja powinna działać (przynajmniej częściowo) przy braku sieci

Co znaczy „odpada” w aplikacjach mobilnych?

Odpada — termin użytkownika opisujący sytuację, gdy aplikacja traci połączenie z serwerem, przestaje reagować na działania lub kończy się błędem. W sensie technicznym może to być: błąd sieciowy (timeout, DNS failure), ANR (blokada wątku UI), crash (nieobsłużony wyjątek) lub race condition (stan wyścigu).

Dla użytkownika wszystkie te scenariusze wyglądają tak samo: aplikacja przestaje działać. Różnica dla programisty polega na podejściu do diagnostyki i naprawy. Błędy sieciowe rozwiązuje się mechanizmami retry, ANR — przenoszeniem operacji poza wątek UI, crash — obsługą wyjątków.

Według Crittercism (obecnie Apteligent), przeciętna aplikacja mobilna traci 1-2% użytkowników przy każdym błędzie. Dla aplikacji z 1 milionem użytkowników to 10-20 tysięcy utraconych instalacji na jeden błąd. Szczególnie krytyczne jest to dla aplikacji w sektorze finansowym i medycznym.

Główne przyczyny utraty połączenia

Niestabilna sieć — urządzenia mobilne stale przełączają się między Wi-Fi a siecią komórkową, wchodzą w strefy bez zasięgu (metro, winda, piwnica). Każde przełączenie powoduje chwilową utratę połączenia, którą aplikacja musi poprawnie obsłużyć.

Timeouty — jeśli serwer nie odpowiada w ustalonym czasie (zwykle 10-30 sekund), klient zgłasza SocketTimeoutException. Długie timeouty bez informacji zwrotnej są odbierane przez użytkownika jako zawieszenie. Zaleca się ustawienie timeoutu nie dłuższego niż 15 sekund.

kotlin
val client = OkHttpClient.Builder()
    .connectTimeout(10, TimeUnit.SECONDS)
    .readTimeout(15, TimeUnit.SECONDS)
    .writeTimeout(15, TimeUnit.SECONDS)
    .retryOnConnectionFailure(true)
    .build()

Stan wyścigu (race condition) — powstaje, gdy wiele wątków jednocześnie czyta i zapisuje te same dane bez synchronizacji. Na przykład ładowanie danych z pamięci podręcznej w wątku UI równolegle z aktualizacją pamięci podręcznej z sieci może prowadzić do wyświetlania nieaktualnych lub nieprawidłowych danych.

  • Nieobsłużone wyjątki w callback lub coroutine prowadzą do awarii aplikacji
  • Memory pressure — system zabija aplikację przy braku pamięci dla aplikacji na pierwszym planie
  • Lifecycle race — operacja async kończy się po zniszczeniu Activity/Fragment
  • Blokada UI — wykonanie sieci lub bazy danych na głównym wątku powoduje ANR po 5 sekundach

Architektura dla niezawodnych aplikacji

Offline-first — wzorzec architektoniczny, w którym lokalne przechowywanie (Room, CoreData) jest jedynym źródłem prawdy. Sieć jest używana do synchronizacji danych w tle. Użytkownik zawsze widzi aktualne dane z lokalnej pamięci podręcznej, nawet przy braku sieci.

Repository pattern — jeden punkt wejścia dla danych, który decyduje, czy pobrać dane z sieci czy z pamięci podręcznej. Repozytorium abstrahuje źródło danych od ViewModel i UI. Przy błędzie sieciowym repozytorium automatycznie przełącza się na lokalne źródło.

kotlin
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) // zwróć pamięć podręczną przy błędzie sieci
            } else {
                Result.failure(e)
            }
        }
    }
}

Circuit Breaker — wzorzec ochrony serwera przed lawiną żądań przy niedostępności. Po N kolejnych błędach wyłącznik otwiera się i wszystkie żądania natychmiast zwracają błąd bez próby połączenia. Po zadanym czasie oczekiwania wyłącznik przechodzi do stanu półotwartego w celu wykonania próbnego żądania.

Jak obsługiwać błędy sieciowe?

Exponential backoff — standardowy mechanizm retry. Po pierwszej porażce odczekaj 1 sekundę, po drugiej — 2 sekundy, następnie 4, 8, 16. Ogranicz maksymalną liczbę prób (zwykle 3-5), aby nie przeciążać serwera i baterii.

Informacja zwrotna dla użytkownika — przy błędzie sieciowym pokaż zrozumiały komunikat: „Brak połączenia”, „Serwer tymczasowo niedostępny”, „Sprawdź internet”. Użyj Snackbar lub Inline State View. Nigdy nie pokazuj użytkownikowi błędów technicznych (HTTP 500, SocketException).

ConnectivityManager — Android API do monitorowania sieci. Pozwól aplikacji reagować na zmiany: przy utracie sieci pokazuj placeholder, przy przywróceniu — automatycznie aktualizuj dane. W iOS używaj NWPathMonitor z frameworku Network.

kotlin
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)
    }
}

Narzędzia monitorowania i logowania

Crashlytics (Firebase) — standardowe narzędzie do raportowania awarii dla aplikacji mobilnych. Zbiera stacktrace wszystkich nieobsłużonych wyjątków, wersję systemu operacyjnego, model urządzenia i czas awarii. Pozwala grupować błędy i przypisywać osoby odpowiedzialne za naprawy.

Sentry — alternatywa dla Crashlytics z obsługą monitorowania wydajności. Pozwala śledzić konkretne transakcje (np. „autoryzacja użytkownika”) i widzieć, na którym kroku wystąpił błąd. Performance tracing pomaga odróżnić timeouty sieciowe od błędów w logice aplikacji.

Timber — biblioteka logowania dla Android z automatycznym dodawaniem tagów według klasy. W kompilacji debug loguj wszystkie żądania sieciowe i odpowiedzi. W kompilacji release — tylko błędy i ostrzeżenia przez Crashlytics.setCustomLog.

NarzędzieTypKiedy używać
CrashlyticsCrash reportingZawsze w release — automatyczne zbieranie awarii
SentryCrash + PerformanceGdy potrzebujesz profilować konkretne scenariusze użytkownika
TimberLoggingDebug: pełne logowanie; Release: tylko błędy
HTTP ToolkitNetwork debugLokalne przechwytywanie i analiza ruchu HTTP

Według Firebase Summit 2023, aplikacje, które wdrożyły Crashlytics + Performance Monitoring, skracają średni czas wykrywania i naprawy krytycznych błędów z 3 dni do 4 godzin. Zaleca się skonfigurowanie alertów na każdy błąd z częstotliwością większą niż 0.1% aktywnych użytkowników.

Często zadawane pytania

Co zrobić, jeśli aplikacja ulega awarii bez komunikatu o błędzie?

Jeśli crash nie jest łapany w Crashlytics, sprawdź native crash (SIGSEGV, SIGABRT) — nie są one obsługiwane przez handler wyjątków Java/Kotlin. W Android może to być wyciek pamięci native z JNI, w iOS — EXC_BAD_ACCESS. Użyj Breakpad (Android) lub PLCrashReporter (iOS) do zbierania stacktrace native crash.

Jak odtworzyć błąd, który występuje tylko przy słabej sieci?

Użyj Network Link Conditioner (wbudowany w iOS, dla Android jest Facebook Network Connection Class lub ustawienia Developer Options > Network > Select network type). Ustaw opóźnienie 500-3000 ms i utratę pakietów 5-30%. Można również użyć Charles Proxy lub mitmproxy do emulacji opóźnień sieciowych i zerwań połączeń.

Jak zapobiec ANR przy żądaniach sieciowych?

ANR występuje, gdy wątek UI jest zablokowany dłużej niż 5 sekund. Żądania sieciowe powinny być wykonywane w wątku tła: coroutines (viewModelScope.launch(Dispatchers.IO)), RxJava (subscribeOn(Schedulers.io)) lub WorkManager do synchronizacji. Zawsze ustawiaj timeouty na kliencie HTTP — brak timeoutu może prowadzić do wiecznej blokady.

Co to jest race condition i jak go uniknąć?

Race condition — sytuacja, w której wynik operacji zależy od kolejności wykonywania wątków. Na przykład użytkownik szybko naciska przycisk „Wyślij” dwa razy i żądanie zostaje wysłane dwukrotnie. Rozwiązanie: użyj Mutex, single-threaded executors lub state machine (wyłącz przycisk po pierwszym naciśnięciu). W Kotlin używaj Mutex z coroutines lub adnotacji @Synchronized.

Jak testować niezawodność aplikacji?

Stosuj Chaos Engineering dla aplikacji mobilnych: wyłączaj sieć podczas operacji, symuluj wysokie opóźnienie, przełączaj między Wi-Fi a siecią komórkową, zabijaj proces przez system. Narzędzia: Facebook Network Connection Class, Charles Proxy, iOS Network Link Conditioner. W CI/CD dodawaj testy UI z różnymi warunkami sieciowymi przez AndroidTest Orchestrator.

Podsumowanie

  • Odpada — termin zbiorczy dla błędów sieciowych, ANR, crash i race conditions; doświadczenie użytkownika jest takie samo, przyczyny różne
  • Błędy sieciowe — najczęstsza przyczyna; rozwiązanie obejmuje timeouty (10-15 sekund), exponential backoff i architekturę offline-first
  • ANR występuje przy blokadzie wątku UI dłuższej niż 5 sekund; operacje sieciowe i dyskowe zawsze wykonuj w wątku tła
  • Offline-first z Repository pattern: lokalne przechowywanie — źródło prawdy, sieć — mechanizm synchronizacji
  • Crashlytics + Performance Monitoring — minimalny zestaw do monitorowania produkcji z alertami na częste awarie
  • Stan wyścigu wymaga synchronizacji wątków: Mutex, State Machine lub jednowątkowy executor
  • Testuj z emulacją słabej sieci i Chaos Engineering — tylko w ten sposób można wykryć problemy ukryte w idealnych warunkach programistycznych

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również