AndroidのANR:原因と修正方法

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

ANR(Application Not Responding)は、アプリが5秒以内に入力に応答しない場合に表示されるAndroidのシステム通知です。グリッチ(UIブロッキングを伴わない論理エラー)やラグ(完全停止を伴わない遅延)とは異なり、ANRはオペレーティングシステムによって記録される重大な障害です。Androidは“アプリが応答していません”というダイアログを表示し、閉じるか待つかのオプションを提供します。Android Vitals Documentationによると、ANR率が0.5%を超えるアプリはGoogle Playでの評価が低くなり、おすすめから非表示になる可能性があります。診断には/data/anr/traces.txtの分析、StrictModeの使用、メインスレッドのプロファイリングが含まれます。

重要なポイント

  • ANR — メインスレッドが5秒以上ブロックされると表示されるAndroidのシステム通知で、“アプリが応答していません”ダイアログが表示される
  • 主な原因 — メインスレッドのブロック(BroadcastReceiver、Service)、スレッド間のデッドロック、ContentProviderでの長時間操作
  • 診断 — /data/anr/traces.txtの分析、Android Studio Profiler、Firebase Performance Monitoring
  • 修正 — WorkManagerへのタスクのオフロード、Dispatchers.IOを使用したKotlin Coroutines、早期発見のためのStrictMode
  • 予防 — BroadcastReceiverの制限時間10秒、Service 20秒、ContentProvider 15秒

AndroidのANRとは

ANR(Application Not Responding)は、アプリが入力に応答しなくなったときに作動するAndroidのユーザー保護メカニズムです。システムはイベント処理時間を追跡します。BroadcastReceiverが10秒以内にonReceiveを完了しない、Serviceが20秒以内にonCreateから戻らない、ContentProviderが15秒以内に応答しない場合、AndroidはANRを生成します。

ユーザーから見たANRの見え方

ANRが発生すると、Androidはすべてのウィンドウの上にシステムダイアログを表示します:「アプリが応答していません。閉じますか、それとも待ちますか?」ユーザーはアプリを閉じるか、回復するのを待つことができます。ANRが頻繁に発生する場合、ユーザーはアプリをアンインストールします。Google PlayはランキングアルゴリズムでANR率(ANRが発生したセッションの割合)を考慮します。

ANRとiOSのフリーズの違い

iOSにはシステムダイアログを伴うANRに相当するものはありません。代わりにAppleはWatchdogを使用し、終了コード0x8badf00dでプロセスを終了します。ユーザーはダイアログを表示されず、アプリは単にホーム画面に閉じられます。これによりAndroidのANRはユーザーにとってより顕著ですが、システムにより多くの診断情報を提供します。

ANRの主な原因

ANRは、システムが4つのコンポーネントタイプのいずれかのタイムアウトを追跡するときに発生します。各コンポーネントには独自の制限時間があります。

BroadcastReceiverでのブロッキング

BroadcastReceiverはメインスレッドで実行されます。onReceiveが同期ネットワークリクエスト、データベースへの長時間書き込み、またはロックの待機を開始すると、10秒以内にANRが発生します。解決策:バックグラウンド処理にはgoAsync()とWorkManagerを使用します。典型的なシナリオは、FCMからプッシュ通知を受信し、Roomに同期的に保存する場合です。

Serviceでの長時間操作

Service.onCreateとService.onStartCommandには20秒の制限があります。サービスがメインスレッドで重い初期化(ライブラリのロード、ネットワークからの設定の読み取り)を開始すると、ANRは避けられません。バックグラウンドでの確実な実行にはIntentService(非推奨)またはWorkManagerを使用します。

初期化が遅いContentProvider

ContentProvider.onCreateはApplication.onCreateの前に実行され、15秒の制限があります。プロバイダーがデータベースマイグレーション、辞書のロード、またはネットワークからのSDK初期化を実行すると、アプリ起動時にANRが発生します。解決策:遅延初期化、重い操作をWorkManagerにオフロードします。

  • BroadcastReceiver — onReceiveに10秒;バックグラウンド処理にはgoAsync()を使用
  • Service — onCreate/onStartCommandに20秒;WorkManagerまたはCoroutineWorkerを使用
  • ContentProvider — onCreateに15秒;遅延起動でApplication.onCreateに初期化を移動
  • UIスレッド — イベント処理なしで5秒;5秒を超えるブロッキングはANRをトリガー

ANRの診断方法

Androidはシステムログから専門ライブラリまで、ANR分析のためのいくつかのツールを提供します。

traces.txtの分析

ANRが発生するたびに、Androidはすべてのアプリスレッドのスタックダンプを含む/data/anr/traces.txtファイルを保存します。“main”スレッドを見つけます。スタックの最後のメソッドが原因を示します。典型的なパターン:Thread.sleep()、InputStream.read()、BinderProxy.transact()。デバイスからファイルを抽出するには、スーパーユーザー権限でadbを使用します。

ANRレポートがあるFirebase Crashlytics

Firebase CrashlyticsはANRを自動的に収集し、トレースとともにダッシュボードに表示します。Android 11+の場合、ANRレポートにはメインスレッドの完全なスタックが含まれます。統合には依存関係の追加とApplication.onCreateでのFirebaseAppの初期化が必要です。

スレッドトレースがあるAndroid Studio Profiler

Android StudioのCPU Profilerを使用すると、アプリのトレースを記録し、どのメソッドがCPU時間を消費しているかを確認できます。“Record with method traces”を有効にし、ANRを引き起こすシナリオを再現します。タイムラインには、フリーズ時にメインスレッドで実行されていたメソッドが表示されます。

AndroidでのANR収集のためのFirebase Crashlytics統合の例:

kotlin
class App : Application() {
    override fun onCreate() {
        super.onCreate()
        FirebaseApp.initializeApp(this)
        FirebaseCrashlytics.getInstance()
            .setCrashlyticsCollectionEnabled(true)
        StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder()
            .detectAll()
            .penaltyLog()
            .build())
    }
}

ANRの修正方法

ANRの修正とは、主にすべての長時間操作をメインスレッドからバックグラウンドスレッドに移動することを意味します。各コンポーネントタイプの具体的なテクニックを見てみましょう。

バックグラウンドタスクのためのWorkManagerの使用

WorkManagerは、バックグラウンド作業に対するGoogleの推奨ソリューションです。デバイスの状態を考慮して、バックグラウンドスレッドでのタスク実行を保証します。Serviceとは異なり、WorkManagerはメインスレッドをブロックせず、アプリの再起動に対して耐性があります。BroadcastReceiverの場合は、goAsync()を使用してPendingResultをWorkManagerに渡します。

適切なディスパッチャーを使用したKotlin Coroutines

すべてのネットワークリクエスト、データベース操作、ファイルI/OはDispatchers.IOで実行します。メインスレッドはUIの更新のみを行うべきです。Activityが破棄されたときにコルーチンを自動キャンセルするにはviewModelScopeを使用します。どのコンテキストでもrunBlocking()は避けてください。現在のスレッドを同期的にブロックします。

ContentProviderの遅延初期化

ContentProviderが遅い初期化を行う場合は、遅延読み込みメカニズムを使用します。即座にデータを返すプロバイダーを作成し、WorkManagerを介して遅延付きで重い初期化を開始します。これにより、システムが遅延に最も敏感なアプリ起動時のANRを防ぎます。

AndroidでgoAsyncを使用したBroadcastReceiverの正しい使用例:

kotlin
class FcmReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        val pendingResult = goAsync()
        WorkManager.getInstance(context!!)
            .enqueue(OneTimeWorkRequest.from(NotificationWorker::class.java))
        pendingResult.finish()
    }
}

開発におけるANRの予防

ANRと戦う最善の方法は、ツールとアーキテクチャ上の決定を通じて開発中にそれらを予防することです。

メインスレッドブロッキング検出のためのStrictMode

有効化されたポリシーdetectNetwork()とdetectDiskReads()/detectDiskWrites()を使用したStrictModeは、開発中に潜在的なANRを特定します。DebugビルドではpenaltyDeathを設定します。違反があると即座にクラッシュが発生し、開発者はコミット前に問題を確認できます。

本番メトリクスのためのFirebase Performance Monitoring

Firebase Performanceは主要な操作の実行時間を追跡し、どのシナリオがANRしきい値を超えているかを示します。各画面とネットワークリクエストにカスタムトレースを設定します。実行時間が3秒を超える場合、最適化が必要な潜在的なANRです。

ネットワークとディスク遅延のテスト

遅い条件をシミュレートします:iOSまたはAndroid EmulatorでNetwork Link Conditionerを使用してネットワーク速度を制限します。低速メモリのエミュレーションを通じてディスク読み取りを遅くします。ANRは多くの場合、このような条件で顕在化し、高速な開発者デバイスでは見えません。

  • BroadcastReceiver — 1秒以上の処理には常にgoAsync()を使用
  • Service — バックグラウンドディスパッチャーを持つWorkManagerまたはCoroutineWorkerに置き換え
  • ContentProvider — onCreateでのネットワークとデータベースを避け、WorkManagerでlazy-initを使用
  • UIスレッド — DebugではpenaltyDeath付きStrictMode、本番監視にはFirebase Performance

よくある質問

なぜANRはAndroidで発生するがiOSでは発生しないのですか?

Androidはメインスレッドのイベント処理時間を明示的に追跡し、ANRダイアログを表示します。iOSはWatchdogを使用し、10~20秒以上フリーズするとアプリを強制的に閉じます。ANRはAndroidアーキテクチャの特徴であり、複数のコンポーネント(BroadcastReceiver、Service)に厳格なタイムアウトがあります。

rootなしでデバイスのtraces.txtを見つける方法は?

Android 11+ではadb shell dumpsys dropbox --print data_app_anrでANRダンプを取得できます。Android 10以下では、rootアクセスなしでは/data/anr/traces.txtにアクセスできません。Firebase Crashlyticsを使用してください。Android 11+ではANRレポートを自動的に収集します。

許容されるANR率はどのくらいですか?

Google PlayはANR率を0.5%未満に推奨しています。つまり、1000セッションあたり5件以下のANRです。率が1%を超えるアプリはGoogle Play Consoleで警告を受け、おすすめから非表示になる可能性があります。理想的にはANR率は0.1%未満であるべきです。

コルーチンはANRを引き起こす可能性がありますか?

コルーチン自体はスレッドをブロックしません。しかし、コルーチン内でメインスレッドでrunBlockingを実行したり、コルーチンがDispatchers.Mainで起動され長いCPU操作を実行すると、ANRが発生します。I/OにはDispatchers.IO、計算にはDispatchers.Defaultを使用します。

エミュレーターでANRをテストする方法は?

“Slow Network”プロファイルのAndroid Emulatorを使用するか、メインスレッドでThread.sleep(6000)を呼び出すテストを記述します。Debugでアプリを起動し、5秒後にANRダイアログが表示されます。logcatにトレース付きのANRレコードが表示されることを確認します。

まとめ

  • ANR — メインスレッドが5秒以上ブロックされるか、コンポーネントのタイムアウトを超えた場合のAndroidシステム通知
  • タイムアウト:BroadcastReceiver — 10秒、Service — 20秒、ContentProvider — 15秒、UI — 5秒
  • 診断 — /data/anr/traces.txt、Firebase Crashlytics、Android StudioのCPU Profiler
  • 修正 — WorkManager、goAsync()、Dispatchers.IOを使用したKotlin Coroutines、ContentProviderの遅延初期化
  • 予防 — penaltyDeath付きStrictMode、Firebase Performance Monitoring、ネットワーク遅延テスト
  • Google PlayはANR率0.5%未満を推奨;率が1%を超えるとアプリの表示が制限される
  • 推奨:本番でのANR収集のためにFirebase CrashlyticsとPerformanceを設定し、しきい値0.3%を超えた場合のアラートを設定

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

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

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

こちらもお読みください