接続切断 — よくある原因と解決方法

著者: IT Sectr 公開日: 2026-07-29 読了時間: 10 分

接続喪失 — モバイルアプリで最も一般的で苛立たしい現象の一つです。ユーザーはデータへのアクセスを失い、操作が中断され、アプリがフリーズしたりクラッシュしたりします。Google Android Developer Blogによると、アプリが2回クラッシュまたはフリーズすると、70%のユーザーがアプリを削除します。接続喪失の原因と、耐障害性のある通信を構築する方法を解説します。

重要なポイント

  • ANR(Application Not Responding)— UIスレッドが5秒以上ブロックされると強制終了される
  • Offline-first — ローカルストレージを信頼できる情報源とし、ネットワークを同期メカニズムとするアーキテクチャ
  • Retry with backoff — ネットワークエラー時に遅延を増やしながら自動的にリクエストを再試行する
  • ConnectivityManager — ネットワーク状態を監視しアプリの動作を適応させるAndroid API
  • Graceful degradation — アプリはネットワーク接続なしでも(少なくとも部分的に)動作すべき

モバイルアプリにおける“接続切断”の意味

接続切断 — アプリがサーバーとの接続を失い、操作に応答しなくなったり、エラーで終了したりする状況を表すユーザー用語です。技術的には、ネットワークエラー(タイムアウト、DNS障害)、ANR(UIスレッドのフリーズ)、クラッシュ(未処理の例外)、またはレースコンディションが考えられます。

ユーザーの視点からは、これらのシナリオはすべて同じに見えます:アプリが動作を停止します。開発者にとっての違いは、診断と修正のアプローチにあります。ネットワークエラーはリトライメカニズムで解決され、ANRはUIスレッドから操作を移すことで、クラッシュは例外処理で対処します。

Crittercism(現Apteligent)によると、モバイルアプリはクラッシュのたびに平均1〜2%のユーザーを失います。100万ユーザーのアプリの場合、1つのバグあたり1万〜2万のインストール損失になります。これは特に金融および医療セクターのアプリにとって重要です。

接続喪失の主な原因

不安定なネットワーク — モバイルデバイスは常に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()

レースコンディション — 複数のスレッドが同期なしに同じデータを同時に読み書きするときに発生します。例えば、UIスレッドでキャッシュからデータを読み込みながらネットワークからキャッシュを更新すると、古いデータや不正確なデータが表示される可能性があります。

  • 未処理の例外がコールバックやコルーチン内で発生するとアプリがクラッシュする
  • メモリプレッシャー — フォアグラウンドアプリに十分なメモリがない場合、システムがアプリを強制終了する
  • ライフサイクルレース — Activity/Fragmentが破棄された後に非同期操作が完了する
  • UIブロッキング — メインスレッドでネットワークやデータベース操作を行うと5秒後にANRが発生する

耐障害性アプリケーションのためのアーキテクチャ

Offline-first — ローカルストレージ(Room、CoreData)を唯一の信頼できる情報源とするアーキテクチャパターンです。ネットワークはバックグラウンドでのデータ同期に使用されます。ユーザーはネットワーク接続がなくても、ローカルキャッシュから常に最新のデータを表示できます。

Repositoryパターン — ネットワークからデータを取得するかキャッシュから取得するかを決定する、データの単一エントリポイントです。リポジトリは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) // return cache on network error
            } else {
                Result.failure(e)
            }
        }
    }
}

サーキットブレーカー — サーバーが利用不可のときにリクエストの殺到から保護するパターンです。N回連続でエラーが発生するとサーキットブレーカーが開き、すべてのリクエストは接続を試みずに即座にエラーを返します。指定されたタイムアウト後、サーキットブレーカーはテストリクエストのために半開き状態に移行します。

ネットワークエラーの対処方法

指数バックオフ — 標準的なリトライメカニズムです。最初の失敗後は1秒待ち、2回目は2秒、その後4、8、16秒と待ちます。サーバーとバッテリーに過負荷をかけないよう、最大リトライ回数(通常3〜5回)を制限してください。

ユーザーフィードバック — ネットワークエラー時には、明確なメッセージを表示します:“接続がありません”、“サーバーが一時的に利用できません”、“インターネット接続を確認してください”。SnackbarやInline State Viewを使用します。絶対に技術的なエラー(HTTP 500、SocketException)をユーザーに表示しないでください。

ConnectivityManager — ネットワーク監視のためのAndroid APIです。アプリが変更に反応できるようにします:接続喪失時にプレースホルダーを表示し、復旧時に自動的にデータを更新します。iOSではNetworkフレームワークのNWPathMonitorを使用します。

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)— モバイルアプリ向けの標準的なクラッシュレポートツールです。すべての未処理例外のスタックトレース、OSバージョン、デバイスモデル、クラッシュ時刻を収集します。エラーをグループ化し、修正責任者を割り当てることができます。

Sentry — パフォーマンス監視をサポートするCrashlyticsの代替ツールです。特定のトランザクション(例:“ユーザー認証”)をトレースし、どのステップでエラーが発生したかを確認できます。パフォーマンストレーシングは、ネットワークタイムアウトとアプリロジックのバグを区別するのに役立ちます。

Timber — クラスごとに自動的にタグを追加するAndroid用ロギングライブラリです。デバッグビルドではすべてのネットワークリクエストとレスポンスをログに記録します。リリースビルドでは、Crashlytics.setCustomLogを介してエラーと警告のみをログに記録します。

ツール種類使用時
Crashlyticsクラッシュレポート常にリリースで — 自動クラッシュ収集
Sentryクラッシュ+パフォーマンス特定のユーザーシナリオをプロファイリングする必要がある場合
Timberロギングデバッグ:完全ロギング;リリース:エラーのみ
HTTP ToolkitネットワークデバッグローカルHTTPトラフィックの傍受と分析

Firebase Summit 2023によると、Crashlytics + Performance Monitoringを実装したアプリは、重大なバグの検出と修正にかかる平均時間を3日から4時間に短縮しました。アクティブユーザーの0.1%を超える頻度のクラッシュごとにアラートを設定することをお勧めします。

よくある質問

アプリがエラーなしでクラッシュする場合の対処法

クラッシュがCrashlyticsで捕捉されない場合、ネイティブクラッシュ(SIGSEGV、SIGABRT)を確認してください。これらはJava/Kotlinの例外ハンドラーでは処理されません。AndroidではJNIからのネイティブメモリリーク、iOSではEXC_BAD_ACCESSが考えられます。ネイティブクラッシュのスタックトレースを収集するには、Breakpad(Android)またはPLCrashReporter(iOS)を使用します。

悪いネットワーク条件下でのみ発生するバグの再現方法

Network Link Conditioner(iOSに内蔵、AndroidではFacebook Network Connection ClassまたはDeveloper Options > Network > Select network typeを使用)を利用します。遅延500〜3000ms、パケットロス5〜30%に設定します。Charles Proxymitmproxyを使用してネットワーク遅延や切断をシミュレートすることもできます。

ネットワークリクエスト中のANRを防ぐ方法

ANRはUIスレッドが5秒以上ブロックされると発生します。ネットワークリクエストはバックグラウンドスレッドで実行する必要があります:コルーチン(viewModelScope.launch(Dispatchers.IO))、RxJava(subscribeOn(Schedulers.io))、または同期用のWorkManagerを使用します。HTTPクライアントには常にタイムアウトを設定してください — タイムアウトがないと永久ブロックの原因になります。

レースコンディションとは何か、どう回避するか

レースコンディション — 操作の結果がスレッド実行の順序に依存する状況です。例えば、ユーザーが“送信”ボタンを素早く2回押すと、リクエストが2回送信されます。解決策:Mutexシングルスレッドエグゼキューター、またはステートマシン(最初のクリック後にボタンを無効化)を使用します。Kotlinでは、コルーチンのMutexまたは@Synchronizedアノテーションを使用します。

アプリケーションの耐障害性をテストする方法

モバイルアプリにカオスエンジニアリングを適用します:操作中にネットワークを切断し、高レイテンシをシミュレートし、Wi-Fiとモバイルネットワークを切り替え、システム経由でプロセスを強制終了します。ツール:Facebook Network Connection ClassCharles ProxyiOS Network Link Conditioner。CI/CDでは、AndroidTest Orchestratorを介して異なるネットワーク条件でのUIテストを追加します。

まとめ

  • 接続切断 — ネットワークエラー、ANR、クラッシュ、レースコンディションを包括する用語;ユーザー体験は同じだが原因は異なる
  • ネットワークエラー — 最も一般的な原因;解決策にはタイムアウト(10〜15秒)、指数バックオフ、オフラインファーストアーキテクチャが含まれる
  • ANRはUIスレッドが5秒以上ブロックされると発生;ネットワークとディスク操作は常にバックグラウンドスレッドで実行する
  • Offline-firstとRepositoryパターン:ローカルストレージが信頼できる情報源、ネットワークは同期メカニズム
  • Crashlytics + Performance Monitoring — 頻繁なクラッシュに対するアラート付きのプロダクション監視の最小セット
  • レースコンディションにはスレッド同期が必要:Mutex、ステートマシン、またはシングルスレッドエグゼキューター
  • テストは悪いネットワークシミュレーションとカオスエンジニアリングで行う — 理想的な開発環境では見えない問題を発見できる唯一の方法

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください