Отпада — шта је то, типични узроци и методе решавања

Аутор: 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 оквира.

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 — минимални сет за производно праћење са упозорењима на честе падове
  • Трка услова захтијева синхронизацију нити: Mutex, State Machine или једнонитни извршилац
  • Тестирајте са емулацијом слабе мреже и Chaos Engineering-ом — само тако можете открити проблеме скривене у идеалним условима развоја

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође