قطع می‌شود — چیست، دلایل معمول و روش‌های حل

نویسنده: IT Sectr منتشر شده: 2026-07-29 زمان مطالعه: 10 دقیقه

از دست رفتن اتصال — یکی از رایج‌ترین و آزاردهنده‌ترین پدیده‌ها در برنامه‌های موبایل است. کاربر دسترسی به داده‌ها را از دست می‌دهد، عملیات قطع می‌شود، برنامه هنگ می‌کند یا کرش می‌کند. طبق Google Android Developer Blog، ۷۰٪ کاربران برنامه‌ای را که دو بار کرش یا هنگ کند حذف می‌کنند. دلایل از دست رفتن اتصال و روش‌های ساخت ارتباطات مقاوم را بررسی می‌کنیم.

نکات کلیدی

  • ANR (Application Not Responding) — مسدود شدن رشته UI بیش از ۵ ثانیه منجر به پایان اجباری می‌شود
  • Offline-first — معماری که در آن ذخیره‌سازی محلی منبع حقیقت است و شبکه مکانیسم همگام‌سازی
  • Retry with backoff — تکرار خودکار درخواست با تأخیر افزایش‌یافته در خطاهای شبکه
  • ConnectivityManager — Android API برای نظارت بر وضعیت شبکه و تطبیق رفتار برنامه
  • Graceful degradation — برنامه باید (حداقل تا حدی) در غیاب شبکه کار کند

«قطع شدن» در برنامه‌های موبایل به چه معناست؟

قطع می‌شود — اصطلاحی کاربردی است که وضعیتی را توصیف می‌کند که برنامه ارتباط خود را با سرور از دست می‌دهد، به اقدامات پاسخ نمی‌دهد یا با خطا پایان می‌یابد. از نظر فنی می‌تواند: خطای شبکه (timeout، DNS failure)، ANR (مسدود شدن رشته UI)، crash (استثنای مدیریت‌نشده) یا race condition (شرط رقابتی) باشد.

برای کاربر همه این سناریوها یکسان به نظر می‌رسند: برنامه از کار می‌افتد. تفاوت برای توسعه‌دهنده در رویکرد تشخیص و رفع است. خطاهای شبکه با مکانیسم‌های retry حل می‌شوند، ANR با خارج کردن عملیات از رشته UI، crash با مدیریت استثناها.

طبق Crittercism (اکنون Apteligent)، یک برنامه موبایل به طور متوسط ۱-۲٪ از کاربران خود را در هر کرش از دست می‌دهد. برای برنامه‌ای با ۱ میلیون کاربر، این ۱۰-۲۰ هزار نصب از دست رفته به ازای هر باگ است. این امر به ویژه برای برنامه‌های بخش مالی و پزشکی بحرانی است.

دلایل اصلی از دست رفتن اتصال

شبکه ناپایدار — دستگاه‌های موبایل دائماً بین Wi-Fi و شبکه موبایل جابه‌جا می‌شوند، وارد مناطق بدون پوشش (مترو، آسانسور، زیرزمین) می‌شوند. هر جابه‌جایی باعث قطع موقت اتصال می‌شود که برنامه باید به درستی مدیریت کند.

تایم‌اوت‌ها — اگر سرور در مدت زمان تعیین‌شده (معمولاً ۱۰-۳۰ ثانیه) پاسخ ندهد، کلاینت SocketTimeoutException صادر می‌کند. تایم‌اوت‌های طولانی بدون بازخورد توسط کاربر به عنوان هنگ تلقی می‌شود. توصیه می‌شود تایم‌اوت بیش از ۱۵ ثانیه تنظیم نشود.

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 می‌شود

معماری برای برنامه‌های مقاوم

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. پس از اولین شکست ۱ ثانیه، پس از دومین ۲ ثانیه، سپس ۴، ۸، ۱۶ صبر کنید. حداکثر تعداد تلاش‌ها را محدود کنید (معمولاً ۳-۵) تا سرور و باتری بیش از حد بارگذاری نشوند.

بازخورد کاربر — در خطای شبکه پیام قابل فهمی نشان دهید: «اتصال برقرار نیست»، «سرور موقتاً در دسترس نیست»، «اینترنت خود را بررسی کنید». از 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 را پیاده‌سازی کرده‌اند، میانگین زمان تشخیص و رفع باگ‌های بحرانی را از ۳ روز به ۴ ساعت کاهش می‌دهند. توصیه می‌شود برای هر کرش با فراوانی بیش از ۰.۱٪ کاربران فعال، هشدار تنظیم کنید.

سوالات متداول

اگر برنامه بدون پیام خطا کرش کرد چه باید کرد؟

اگر crash در Crashlytics گرفته نمی‌شود، native crash (SIGSEGV, SIGABRT) را بررسی کنید — آنها توسط handler استثنای 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) استفاده کنید. تأخیر را ۵۰۰-۳۰۰۰ ms و افت بسته را ۵-۳۰٪ تنظیم کنید. همچنین می‌توانید از Charles Proxy یا mitmproxy برای شبیه‌سازی تأخیرهای شبکه و قطعی‌ها استفاده کنید.

چگونه از ANR در درخواست‌های شبکه جلوگیری کنیم؟

ANR زمانی رخ می‌دهد که رشته UI بیش از ۵ ثانیه مسدود شود. درخواست‌های شبکه باید در رشته پس‌زمینه اجرا شوند: 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 اضافه کنید.

خلاصه

  • قطع می‌شود — اصطلاحی جامع برای خطاهای شبکه، ANR، crash و race conditions; تجربه کاربر یکسان است، دلایل متفاوت
  • خطاهای شبکه — شایع‌ترین دلیل; راه‌حل شامل تایم‌اوت‌ها (۱۰-۱۵ ثانیه)، exponential backoff و معماری offline-first است
  • ANR با مسدود شدن رشته UI بیش از ۵ ثانیه رخ می‌دهد; عملیات شبکه و دیسک را همیشه در رشته پس‌زمینه اجرا کنید
  • Offline-first با Repository pattern: ذخیره‌سازی محلی — منبع حقیقت، شبکه — مکانیسم همگام‌سازی
  • Crashlytics + Performance Monitoring — حداقل مجموعه برای نظارت production با هشدار روی کرش‌های مکرر
  • شرط رقابتی نیازمند همگام‌سازی رشته‌ها: Mutex، State Machine یا executor تک‌رشته‌ای
  • تست کنید با شبیه‌سازی شبکه ضعیف و Chaos Engineering — تنها در این صورت می‌توان مشکلات پنهان در شرایط ایده‌آل توسعه را کشف کرد

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید