ANR trong Android: nó là gì, nguyên nhân và phương pháp khắc phục

Tác giả: IT Sectr Đã đăng: 2026-07-28 Thời gian đọc: 9 phút

ANR (Application Not Responding) là một thông báo hệ thống trong Android xuất hiện khi ứng dụng không phản hồi đầu vào trong vòng 5 giây. Khác với lỗi vặt (lỗi logic không chặn UI) và lag (chậm mà không dừng hoàn toàn), ANR là một lỗi nghiêm trọng được hệ điều hành ghi lại: Android hiển thị hộp thoại “Ứng dụng không phản hồi” với tùy chọn đóng hoặc chờ. Theo Android Vitals Documentation, các ứng dụng có tỷ lệ ANR trên 0,5% sẽ bị xếp hạng thấp hơn trên Google Play và có thể bị ẩn khỏi các đề xuất. Chẩn đoán bao gồm phân tích /data/anr/traces.txt, sử dụng StrictMode và cấu hình hồ sơ luồng chính.

Những điểm chính

  • ANR — một thông báo hệ thống trong Android khi luồng chính bị chặn hơn 5 giây, dẫn đến hộp thoại “Ứng dụng không phản hồi”
  • Nguyên nhân chính — chặn luồng chính (BroadcastReceiver, Service), deadlock giữa các luồng, thao tác dài trong ContentProvider
  • Chẩn đoán — phân tích /data/anr/traces.txt, Android Studio Profiler, Firebase Performance Monitoring
  • Khắc phục — chuyển tác vụ sang WorkManager, sử dụng Kotlin Coroutines với Dispatchers.IO, StrictMode để phát hiện sớm
  • Phòng ngừa — giới hạn thời gian BroadcastReceiver 10 giây, Service 20 giây, ContentProvider 15 giây

ANR trong Android là gì

ANR (Application Not Responding) là một cơ chế bảo vệ người dùng trong Android được kích hoạt khi ứng dụng ngừng phản hồi đầu vào. Hệ thống theo dõi thời gian xử lý sự kiện: nếu BroadcastReceiver không hoàn thành onReceive trong 10 giây, Service không trở về từ onCreate trong 20 giây, hoặc ContentProvider không phản hồi trong 15 giây — Android tạo ra ANR.

ANR trông như thế nào đối với người dùng

Khi ANR xảy ra, Android hiển thị hộp thoại hệ thống trên tất cả cửa sổ: “Ứng dụng không phản hồi. Bạn muốn đóng hay chờ?” Người dùng có thể đóng ứng dụng hoặc chờ nó khôi phục. Nếu ANR xảy ra thường xuyên, người dùng sẽ gỡ cài đặt ứng dụng. Google Play xem xét tỷ lệ ANR — phần trăm phiên có ANR — trong các thuật toán xếp hạng của mình.

Sự khác biệt giữa ANR và treo trên iOS

iOS không có tương đương ANR với hộp thoại hệ thống. Thay vào đó, Apple sử dụng Watchdog, kết thúc tiến trình với mã thoát 0x8badf00d. Người dùng không thấy hộp thoại — ứng dụng chỉ đơn giản đóng lại về màn hình chính. Điều này làm cho ANR trên Android dễ thấy hơn đối với người dùng nhưng cung cấp cho hệ thống nhiều thông tin chẩn đoán hơn.

Nguyên nhân chính của ANR

ANR xảy ra khi hệ thống theo dõi thời gian chờ cho một trong bốn loại thành phần. Mỗi thành phần có giới hạn thời gian riêng.

Chặn trong BroadcastReceiver

BroadcastReceiver được thực thi trong luồng chính. Nếu onReceive bắt đầu một yêu cầu mạng đồng bộ, ghi dài vào cơ sở dữ liệu hoặc chờ khóa — ANR sẽ xảy ra trong vòng 10 giây. Giải pháp: sử dụng goAsync() và WorkManager để xử lý nền. Kịch bản điển hình là nhận thông báo Push từ FCM và lưu đồng bộ vào Room.

Thao tác dài trong Service

Service.onCreate và Service.onStartCommand có giới hạn 20 giây. Nếu dịch vụ bắt đầu khởi tạo nặng (tải thư viện, đọc cấu hình từ mạng) trong luồng chính — ANR là không thể tránh khỏi. Sử dụng IntentService (lỗi thời) hoặc WorkManager để thực thi đảm bảo trong nền.

ContentProvider với khởi tạo chậm

ContentProvider.onCreate được thực thi trước Application.onCreate và có giới hạn 15 giây. Nếu nhà cung cấp thực hiện di chuyển cơ sở dữ liệu, tải từ điển hoặc khởi tạo SDK từ mạng — điều này gây ra ANR khi khởi động ứng dụng. Giải pháp: khởi tạo trễ, chuyển các thao tác nặng sang WorkManager.

  • BroadcastReceiver — 10 giây cho onReceive; sử dụng goAsync() để xử lý nền
  • Service — 20 giây cho onCreate/onStartCommand; sử dụng WorkManager hoặc CoroutineWorker
  • ContentProvider — 15 giây cho onCreate; di chuyển khởi tạo sang Application.onCreate với khởi chạy trễ
  • Luồng UI — 5 giây không xử lý sự kiện; bất kỳ chặn nào hơn 5 giây sẽ kích hoạt ANR

Cách chẩn đoán ANR

Android cung cấp một số công cụ để phân tích ANR: từ nhật ký hệ thống đến các thư viện chuyên dụng.

Phân tích traces.txt

Ở mỗi ANR, Android lưu tệp /data/anr/traces.txt với kết xuất ngăn xếp của tất cả các luồng ứng dụng. Tìm luồng “main” — phương thức cuối cùng trong ngăn xếp chỉ ra nguyên nhân. Các mẫu điển hình: Thread.sleep(), InputStream.read(), BinderProxy.transact(). Để trích xuất tệp từ thiết bị, sử dụng adb với quyền siêu người dùng.

Firebase Crashlytics với báo cáo ANR

Firebase Crashlytics tự động thu thập ANR và hiển thị chúng trong bảng điều khiển với dấu vết. Đối với Android 11+, báo cáo ANR đi kèm với ngăn xếp đầy đủ của luồng chính. Tích hợp yêu cầu thêm phụ thuộc và khởi tạo FirebaseApp trong Application.onCreate.

Android Studio Profiler với theo dõi luồng

CPU Profiler trong Android Studio cho phép bạn ghi lại dấu vết ứng dụng và xem phương thức nào tiêu tốn thời gian CPU. Bật “Record with method traces” và tái tạo kịch bản gây ra ANR. Dòng thời gian sẽ hiển thị phương thức nào đang chạy trong luồng chính tại thời điểm treo.

Ví dụ tích hợp Firebase Crashlytics để thu thập ANR trên Android:

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

Phương pháp khắc phục ANR

Khắc phục ANR chủ yếu có nghĩa là di chuyển tất cả các thao tác dài từ luồng chính sang các luồng nền. Hãy xem các kỹ thuật cụ thể cho từng loại thành phần.

Sử dụng WorkManager cho tác vụ nền

WorkManager là giải pháp được Google khuyên dùng cho công việc nền. Nó đảm bảo thực thi tác vụ trong luồng nền có tính đến trạng thái thiết bị. Khác với Service, WorkManager không chặn luồng chính và có khả năng chống chịu với việc khởi động lại ứng dụng. Đối với BroadcastReceiver, sử dụng goAsync() và chuyển PendingResult cho WorkManager.

Kotlin Coroutines với bộ điều phối phù hợp

Chạy tất cả các yêu cầu mạng, thao tác cơ sở dữ liệu và I/O tệp với Dispatchers.IO. Luồng chính chỉ nên cập nhật UI. Sử dụng viewModelScope để tự động hủy coroutine khi Activity bị phá hủy. Tránh runBlocking() trong bất kỳ ngữ cảnh nào — nó chặn luồng hiện tại một cách đồng bộ.

Khởi tạo trễ ContentProvider

Nếu ContentProvider thực hiện khởi tạo chậm, hãy sử dụng cơ chế tải trễ: tạo một nhà cung cấp trả về dữ liệu ngay lập tức và bắt đầu khởi tạo nặng thông qua WorkManager với độ trễ. Điều này ngăn chặn ANR khi khởi động ứng dụng, khi hệ thống nhạy cảm nhất với độ trễ.

Ví dụ sử dụng đúng BroadcastReceiver với goAsync trong Android:

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()
    }
}

Phòng ngừa ANR trong phát triển

Cách tốt nhất để chống lại ANR là ngăn chặn chúng trong quá trình phát triển thông qua các công cụ và quyết định kiến trúc.

StrictMode để phát hiện chặn luồng chính

StrictMode với các chính sách detectNetwork() và detectDiskReads()/detectDiskWrites() được bật sẽ xác định các ANR tiềm ẩn trong quá trình phát triển. Trong bản dựng Debug, đặt penaltyDeath — bất kỳ vi phạm nào sẽ gây ra sự cố ngay lập tức và nhà phát triển sẽ thấy vấn đề trước khi commit.

Firebase Performance Monitoring cho chỉ số sản xuất

Firebase Performance theo dõi thời gian thực thi của các thao tác chính và hiển thị kịch bản nào vượt quá ngưỡng ANR. Thiết lập dấu vết tùy chỉnh cho mỗi màn hình và yêu cầu mạng. Nếu thời gian thực thi vượt quá 3 giây — đó là ANR tiềm ẩn cần tối ưu hóa.

Kiểm thử với độ trễ mạng và đĩa

Mô phỏng các điều kiện chậm: giới hạn tốc độ mạng bằng Network Link Conditioner trên iOS hoặc Android Emulator. Làm chậm đọc đĩa thông qua mô phỏng bộ nhớ chậm. ANR thường xuất hiện chính xác trong những điều kiện này; trên các thiết bị phát triển nhanh, chúng không nhìn thấy.

  • BroadcastReceiver — luôn sử dụng goAsync() cho xử lý hơn 1 giây
  • Service — thay thế bằng WorkManager hoặc CoroutineWorker với bộ điều phối nền
  • ContentProvider — tránh mạng và cơ sở dữ liệu trong onCreate, sử dụng lazy-init với WorkManager
  • Luồng UI — StrictMode với penaltyDeath trong Debug, Firebase Performance để giám sát sản xuất

Câu hỏi thường gặp

Tại sao ANR xảy ra trên Android nhưng không trên iOS?

Android theo dõi thời gian xử lý sự kiện trên luồng chính một cách rõ ràng và hiển thị hộp thoại ANR. iOS sử dụng Watchdog, đóng cưỡng bức ứng dụng khi nó treo hơn 10–20 giây. ANR là một đặc điểm của kiến trúc Android nơi nhiều thành phần (BroadcastReceiver, Service) có thời gian chờ nghiêm ngặt.

Làm thế nào để tìm traces.txt trên thiết bị không có root?

Trên Android 11+, bạn có thể lấy kết xuất ANR qua adb shell dumpsys dropbox --print data_app_anr. Trên Android 10 trở xuống, không có quyền root thì không thể truy cập /data/anr/traces.txt. Sử dụng Firebase Crashlytics — nó tự động thu thập báo cáo ANR cho Android 11+.

Tỷ lệ ANR nào được coi là chấp nhận được?

Google Play khuyên nghị tỷ lệ ANR dưới 0,5% — không quá 5 ANR trên 1000 phiên. Ứng dụng có tỷ lệ trên 1% sẽ nhận được cảnh báo trong Google Play Console và có thể bị ẩn khỏi các đề xuất. Lý tưởng nhất, tỷ lệ ANR nên dưới 0,1%.

Coroutine có thể gây ra ANR không?

Bản thân coroutine không chặn luồng. Nhưng nếu bên trong coroutine bạn thực thi runBlocking trên luồng chính hoặc coroutine được khởi chạy với Dispatchers.Main và thực hiện thao tác CPU dài — điều này sẽ gây ra ANR. Sử dụng Dispatchers.IO cho I/O và Dispatchers.Default cho tính toán.

Làm thế nào để kiểm thử ANR trong trình giả lập?

Sử dụng Android Emulator với hồ sơ “Slow Network” hoặc viết một bài kiểm thử gọi Thread.sleep(6000) trên luồng chính. Khởi chạy ứng dụng qua Debug và sau 5 giây bạn sẽ thấy hộp thoại ANR. Kiểm tra rằng logcat hiển thị bản ghi ANR với dấu vết.

Tổng kết

  • ANR — một thông báo hệ thống trong Android khi luồng chính bị chặn hơn 5 giây hoặc vượt quá thời gian chờ của thành phần
  • Thời gian chờ: BroadcastReceiver — 10 giây, Service — 20 giây, ContentProvider — 15 giây, UI — 5 giây
  • Chẩn đoán — /data/anr/traces.txt, Firebase Crashlytics, CPU Profiler trong Android Studio
  • Khắc phục — WorkManager, goAsync(), Kotlin Coroutines với Dispatchers.IO, khởi tạo trễ ContentProvider
  • Phòng ngừa — StrictMode với penaltyDeath, Firebase Performance Monitoring, kiểm thử với độ trễ mạng
  • Google Play khuyên nghị tỷ lệ ANR < 0,5%; với tỷ lệ > 1% ứng dụng bị hạn chế hiển thị
  • Khuyên nghị: thiết lập Firebase Crashlytics và Performance để thu thập ANR trong sản xuất và đặt cảnh báo khi vượt quá ngưỡng 0,3%

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm