Прекъсва се — какво е, типични причини и методи за решаване

Автор: IT Sectr Публикувано: 2026-07-29 Време за четене: 10 мин

Загуба на връзка — едно от най-честите и дразнещи явления в мобилните приложения. Потребителят губи достъп до данни, операцията се прекъсва, приложението замръзва или крашва. Според Google Android Developer Blog, 70% от потребителите изтриват приложението, ако то крашне или замръзне два пъти. Нека разгледаме причините за загуба на връзка и начините за изграждане на устойчиви комуникации.

Основни точки

  • ANR (Application Not Responding) — блокиране на UI нишката за повече от 5 секунди води до принудително прекратяване
  • Offline-first — архитектура, при която локалното хранилище е източник на истина, а мрежата е механизъм за синхронизация
  • Retry with backoff — автоматично повторение на заявката с нарастващо забавяне при мрежови грешки
  • ConnectivityManager — Android API за проследяване на състоянието на мрежата и адаптиране на поведението на приложението
  • Graceful degradation — приложението трябва да работи (поне частично) при липса на мрежа

Какво означава „прекъсва се” в мобилните приложения?

Прекъсва се — потребителски термин, описващ ситуация, когато приложението губи връзка със сървъра, спира да отговаря на действия или завършва с грешка. В технически смисъл това може да бъде: мрежова грешка (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 секунди.

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

Състояние на надпревара (race condition) — възниква, когато множество нишки едновременно четат и пишат едни и същи данни без синхронизация. Например, зареждане на данни от кеша в UI нишката паралелно с обновяване на кеша от мрежата може да доведе до показване на остарели или некоректни данни.

  • Необработени изключения в callback или coroutine водят до крашване на приложението
  • Натиск върху паметта — системата убива приложението при липса на памет за приложението на преден план
  • Lifecycle race — async операция завършва след като Activity/Fragment е унищожен
  • Блокиране на UI — изпълнение на мрежа или база данни в главната нишка причинява ANR след 5 секунди

Архитектура за устойчиви приложения

Offline-first — архитектурен модел, при който локалното хранилище (Room, CoreData) е единственият източник на истина. Мрежата се използва за синхронизация на данни във фонов режим. Потребителят винаги вижда актуални данни от локалния кеш, дори при липса на мрежа.

Repository pattern — единна входна точка за данни, която решава дали данните да се вземат от мрежата или от кеша. Репозиторието абстрахира източника на данни от ViewModel и UI. При мрежова грешка репозиторието автоматично превключва към локалния източник.

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) // върни кеш при мрежова грешка
            } 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 framework.

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

Инструменти за мониторинг и логване

Crashlytics (Firebase) — стандартен инструмент за отчитане на крашвания за мобилни приложения. Събира stacktrace на всички необработени изключения, версия на ОС, модел на устройство и време на крашване. Позволява групиране на грешки и назначаване на отговорници за поправки.

Sentry — алтернатива на Crashlytics с поддръжка на мониторинг на производителността. Позволява проследяване на конкретни транзакции (напр. „автентикация на потребител”) и виждане на коя стъпка е възникнала грешката. Performance tracing помага да се разграничат мрежовите таймаути от бъгове в логиката на приложението.

Timber — библиотека за логване за Android с автоматично добавяне на тагове според класа. В debug сборка логвайте всички мрежови заявки и отговори. В release сборка — само грешки и предупреждения чрез Crashlytics.setCustomLog.

ИнструментТипКога да използваме
CrashlyticsCrash reportingВинаги в release — автоматично събиране на крашвания
SentryCrash + PerformanceКогато трябва да профилирате конкретни потребителски сценарии
TimberLoggingDebug: пълно логване; Release: само грешки
HTTP ToolkitNetwork debugЛокално прихващане и анализ на HTTP трафик

Според Firebase Summit 2023, приложенията, внедрили Crashlytics + Performance Monitoring, намаляват средното време за откриване и поправка на критични бъгове от 3 дни до 4 часа. Препоръчва се настройка на аларми за всяко крашване с честота над 0.1% от активните потребители.

Често задавани въпроси

Какво да правим, ако приложението крашва без съобщение за грешка?

Ако crash не се хваща в Crashlytics, проверете native crash (SIGSEGV, SIGABRT) — те не се обработват от Java/Kotlin exception handler. В 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 при мрежови заявки?

ANR възниква, когато UI нишката е блокирана повече от 5 секунди. Мрежовите заявки трябва да се изпълняват във фонова нишка: coroutines (viewModelScope.launch(Dispatchers.IO)), RxJava (subscribeOn(Schedulers.io)) или WorkManager за синхронизация. Винаги задавайте таймаути на HTTP клиента — липсата на таймаут може да доведе до вечно блокиране.

Какво е race condition и как да го избегнем?

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.

Резюме

  • Прекъсва се — сборен термин за мрежови грешки, ANR, crash и race conditions; потребителското изживяване е същото, причините са различни
  • Мрежови грешки — най-честата причина; решението включва таймаути (10-15 секунди), exponential backoff и offline-first архитектура
  • ANR възниква при блокиране на UI нишката повече от 5 секунди; мрежовите и дисковите операции винаги изпълнявайте във фонова нишка
  • Offline-first с Repository pattern: локално хранилище — източник на истина, мрежа — механизъм за синхронизация
  • Crashlytics + Performance Monitoring — минимален набор за production мониторинг с аларми за чести крашвания
  • Състояние на надпревара изисква синхронизация на нишки: Mutex, State Machine или еднонишков изпълнител
  • Тествайте с емулация на слаба мрежа и Chaos Engineering — само така можете да откриете проблеми, скрити в идеални условия на разработка

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също