Bağlantı kaybı — mobil uygulamalardaki en yaygın ve sinir bozucu olaylardan biridir. Kullanıcı verilere erişimini kaybeder, işlem kesintiye uğrar, uygulama donar veya çöker. Google Android Developer Blog’a göre, kullanıcıların %70’i bir uygulama iki kez çöker veya donarsa onu siler. Bağlantı kaybının nedenlerini ve hataya dayanıklı iletişim kurma yollarını inceleyelim.
Önemli Noktalar
Bağlantı kopması — uygulamanın sunucuyla bağlantısını kaybettiği, eylemlere yanıt vermeyi bıraktığı veya bir hatayla sonlandığı durumu tanımlayan bir kullanıcı terimidir. Teknik olarak bu şunlar olabilir: ağ hatası (zaman aşımı, DNS hatası), ANR (UI iş parçacığının donması), çökme (işlenmemiş istisna) veya yarışma koşulu (race condition).
Kullanıcının bakış açısından, tüm bu senaryolar aynı görünür: uygulama çalışmayı durdurur. Geliştiriciler için fark, tanı ve düzeltme yaklaşımındadır. Ağ hataları yeniden deneme mekanizmalarıyla, ANR işlemlerin UI iş parçacığından taşınmasıyla, çökmeler istisna işlemeyle çözülür.
Crittercism (şimdi Apteligent)’e göre, bir mobil uygulama her çökmede ortalama %1–2 oranında kullanıcı kaybeder. 1 milyon kullanıcılı bir uygulama için bu, tek bir hata başına 10–20 bin kayıp kurulum anlamına gelir. Bu özellikle finans ve tıp sektörlerindeki uygulamalar için kritiktir.
Dengesiz ağ — mobil cihazlar sürekli olarak Wi-Fi ve mobil ağ arasında geçiş yapar, kapsama alanı olmayan bölgelere (metro, asansör, bodrum) girer. Her geçiş, uygulamanın doğru şekilde ele alması gereken geçici bir bağlantı kaybına neden olur.
Zaman aşımları — sunucu belirlenen zaman aşımı (genellikle 10–30 saniye) içinde yanıt vermezse, istemci SocketTimeoutException fırlatır. Geri bildirim olmadan uzun zaman aşımları kullanıcı tarafından donma olarak algılanır. Zaman aşımının 15 saniyeden fazla olmaması önerilir.
val client = OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build()
Yarışma koşulu (race condition) — birden çok iş parçacığının eşzamanlı olarak aynı verileri senkronizasyon olmadan okuması ve yazmasıyla oluşur. Örneğin, ağdan önbelleği güncellerken UI iş parçacığında önbellekten veri yüklemek, güncel olmayan veya yanlış verilerin görüntülenmesine yol açabilir.
Offline-first — yerel depolamanın (Room, CoreData) tek gerçek kaynağı olduğu bir mimari desendir. Ağ, arka planda veri senkronizasyonu için kullanılır. Kullanıcı, ağ bağlantısı olmasa bile yerel önbellekten her zaman güncel verileri görür.
Repository deseni — verilerin ağdan mı yoksa önbellekten mi alınacağına karar veren tek bir giriş noktasıdır. Repository, ViewModel ve UI’dan veri kaynağını soyutlar. Ağ hatası durumunda, repository otomatik olarak yerel kaynağa geçer.
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)
}
}
}
}
Devre Kesici (Circuit Breaker) — sunucu kullanılamadığında onu istek yağmurundan koruyan bir desendir. Ardışık N hatadan sonra devre kesici açılır ve tüm istekler bağlantı kurmayı denemeden hemen bir hata döndürür. Belirli bir zaman aşımından sonra, devre kesici bir test isteği için yarı açık duruma geçer.
Üstel geri çekilme (Exponential backoff) — standart bir yeniden deneme mekanizmasıdır. İlk başarısızlıktan sonra 1 saniye bekleyin; ikinciden sonra 2 saniye; ardından 4, 8, 16. Sunucuyu ve pili aşırı yüklememek için maksimum yeniden deneme sayısını (genellikle 3–5) sınırlayın.
Kullanıcı geri bildirimi — ağ hatasında net bir mesaj gösterin: “Bağlantı yok”, “Sunucu geçici olarak kullanılamıyor”, “İnternet bağlantınızı kontrol edin”. Snackbar veya Inline State View kullanın. Kullanıcıya asla teknik hataları (HTTP 500, SocketException) göstermeyin.
ConnectivityManager — ağ izleme için Android API’sidir. Uygulamanın değişikliklere tepki vermesine izin verin: bağlantı kaybında bir yer tutucu gösterin, geri yüklemede otomatik olarak verileri güncelleyin. iOS’ta Network çerçevesinden NWPathMonitor’u kullanın.
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) — mobil uygulamalar için standart bir çökme raporlama aracıdır. Tüm işlenmemiş istisnaların yığın izlerini, işletim sistemi sürümünü, cihaz modelini ve çökme zamanını toplar. Hataları gruplamaya ve düzeltmeler için sorumlu kişiler atamaya olanak tanır.
Sentry — performans izleme desteğiyle Crashlytics’e bir alternatiftir. Belirli işlemleri (örneğin, “kullanıcı yetkilendirmesi”) izlemeye ve hatanın hangi adımda oluştuğunu görmeye olanak tanır. Performans izleme, ağ zaman aşımlarını uygulama mantığındaki hatalardan ayırt etmeye yardımcı olur.
Timber — sınıfa göre otomatik etiket ekleme özelliğine sahip Android için bir günlük kaydı kütüphanesidir. Hata ayıklama yapılarında tüm ağ isteklerini ve yanıtlarını kaydedin. Sürüm yapılarında, Crashlytics.setCustomLog aracılığıyla yalnızca hataları ve uyarıları kaydedin.
| Araç | Tür | Ne zaman kullanılmalı |
|---|---|---|
| Crashlytics | Çökme raporlama | Her zaman sürümde — otomatik çökme toplama |
| Sentry | Çökme + Performans | Belirli kullanıcı senaryolarını profillemeniz gerektiğinde |
| Timber | Günlük kaydı | Hata ayıklama: tam günlük; Sürüm: yalnızca hatalar |
| HTTP Toolkit | Ağ hata ayıklama | Yerel HTTP trafiğini yakalama ve analiz etme |
Firebase Summit 2023’e göre, Crashlytics + Performance Monitoring’i uygulayan uygulamalar, kritik hataları tespit etme ve düzeltme ortalama süresini 3 günden 4 saate düşürür. Aktif kullanıcıların %0,1’inden daha sık görülen her çökme için uyarılar ayarlamanız önerilir.
Sıkça Sorulan Sorular
Bir çökme Crashlytics’te yakalanmazsa, yerel çökmeleri (SIGSEGV, SIGABRT) kontrol edin — bunlar Java/Kotlin istisna işleyicisi tarafından işlenmez. Android’de bu, JNI’den yerel bellek sızıntısı olabilir; iOS’ta EXC_BAD_ACCESS. Yerel çökme yığın izlerini toplamak için Breakpad (Android) veya PLCrashReporter (iOS) kullanın.
Network Link Conditioner (iOS’ta yerleşik; Android için Facebook Network Connection Class veya Developer Options > Network > Select network type kullanın) kullanın. 500–3000 ms gecikme ve %5–30 paket kaybı ayarlayın. Ağ gecikmesini ve bağlantı kesilmelerini simüle etmek için Charles Proxy veya mitmproxy de kullanabilirsiniz.
ANR, UI iş parçacığı 5 saniyeden fazla bloke edildiğinde oluşur. Ağ istekleri bir arka plan iş parçacığında yürütülmelidir: coroutine (viewModelScope.launch(Dispatchers.IO)), RxJava (subscribeOn(Schedulers.io)) veya senkronizasyon için WorkManager. HTTP istemcisinde her zaman zaman aşımı ayarlayın — zaman aşımının olmaması kalıcı blokaja yol açabilir.
Yarışma koşulu — bir işlemin sonucunun iş parçacığı yürütme sırasına bağlı olduğu bir durumdur. Örneğin, bir kullanıcı “Gönder” düğmesine hızla iki kez basar ve istek iki kez gönderilir. Çözüm: Mutex, tek iş parçacıklı yürütücüler veya bir durum makinesi kullanın (ilk tıklamadan sonra düğmeyi devre dışı bırakın). Kotlin’de, coroutine’lerden Mutex veya @Synchronized ek açıklamasını kullanın.
Mobil uygulamalar için Kaos Mühendisliği (Chaos Engineering) uygulayın: işlemler sırasında ağı kesin, yüksek gecikme simüle edin, Wi-Fi ve mobil ağ arasında geçiş yapın, sistem üzerinden işlemi öldürün. Araçlar: Facebook Network Connection Class, Charles Proxy, iOS Network Link Conditioner. CI/CD’de, AndroidTest Orchestrator aracılığıyla farklı ağ koşullarıyla UI testleri ekleyin.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun