Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang
Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.
Hình 1. Hộp thoại ANR hiển thị cho người dùng.
Tài liệu này mô tả cách hệ thống Android xác định liệu một ứng dụng có phản hồi hay không và hướng dẫn cách duy trì khả năng phản hồi của ứng dụng.
Bất kể mã của bạn được viết chính xác đến mức nào, ứng dụng vẫn có thể bị chậm, treo, đơ trong một khoảng thời gian đáng kể hoặc mất quá nhiều thời gian để xử lý thông tin đầu vào. Nếu ứng dụng của bạn chạy ở nền trước và không phản hồi, thì người dùng sẽ thấy hộp thoại Ứng dụng không phản hồi (ANR), như minh hoạ trong hình 1. Khi hộp thoại ANR xuất hiện, người dùng có thể buộc thoát khỏi ứng dụng. Nếu không chạy ở nền trước, thì ứng dụng sẽ tự động dừng. Điều quan trọng là bạn phải thiết kế khả năng phản hồi cho ứng dụng để giảm thiểu hộp thoại ANR.
Điều kiện kích hoạt ANR
Nhìn chung, hệ thống sẽ hiển thị một hộp thoại ANR nếu một ứng dụng không thể phản hồi hoạt động đầu vào của người dùng trên luồng chính (còn gọi là luồng giao diện người dùng). Điều này sẽ ngăn hệ thống xử lý các sự kiện đến từ hoạt động đầu vào của người dùng.
Ví dụ: lỗi ANR có thể xảy ra nếu một ứng dụng thực hiện một thao tác chặn I/O (chẳng hạn như quyền truy cập mạng) trên luồng giao diện người dùng. Ví dụ khác là trong trường hợp một ứng dụng dành quá nhiều thời gian cho việc xây dựng một cấu trúc chi tiết trong bộ nhớ hoặc tính toán bước tiếp theo trong một trò chơi trên luồng giao diện người dùng.
Trong Android, khả năng phản hồi của ứng dụng được các dịch vụ hệ thống ActivityManager và WindowManager giám sát. Android hiển thị hộp thoại ANR cho ứng dụng khi phát hiện thấy một trong các điều kiện sau xảy ra:
Không phản hồi một sự kiện đầu vào (chẳng hạn như sự kiện nhấn phím hoặc nhấn vào màn hình) trong vòng 5 giây.
Dưới đây là những lưu ý chung giúp tránh lỗi ANR. Nếu bạn muốn biết thêm thông tin chi tiết về cách chẩn đoán và gỡ nhiều loại lỗi ANR, hãy xem các trang khác trong phần này.
Luôn bỏ chặn luồng chính và sử dụng các luồng một cách có chiến lược.
Không thực hiện các thao tác chặn hoặc chạy trong thời gian dài trên luồng chính của ứng dụng.
Thay vào đó, hãy tạo một luồng worker và thực hiện hầu hết thao tác ở đó.
Cố gắng giảm thiểu mọi trường hợp tranh chấp khoá giữa luồng chính và các luồng khác.
Giảm thiểu mọi thao tác không liên quan đến giao diện người dùng trên luồng chính, chẳng hạn như khi xử lý thông báo truyền tin hoặc chạy các dịch vụ. Mọi phương thức chạy trong luồng giao diện người dùng đều phải thực hiện ít hoạt động nhất có thể trên luồng đó. Cụ thể, phải thực hiện càng ít hoạt động càng tốt để thiết lập các phương thức chính trong vòng đời, chẳng hạn như onCreate() và onResume(). Hãy xem bài viết Tổng quan về hoạt động trong nền nếu bạn muốn biết thêm thông tin về các giải pháp hiện có để lên lịch hoạt động trong luồng ở chế độ nền và giao tiếp trở lại với giao diện người dùng.
Thận trọng khi chia sẻ nhóm luồng giữa các thành phần. Không dùng cùng một luồng cho các thao tác chặn có thể diễn ra trong thời gian dài và các tác vụ có giới hạn thời gian, chẳng hạn như tác vụ nhận thông báo truyền tin.
Giúp ứng dụng khởi động nhanh. Giảm thiểu các thao tác chặn hoặc làm chậm tốc độ trong mã khởi động của ứng dụng, chẳng hạn như các phương thức chạy trong quá trình khởi chạy Dagger.
Nếu bạn sử dụng goAsync(), hãy đảm bảo rằng PendingResult.finish sẽ nhanh chóng được gọi trước khi hết thời gian chờ ANR.
Lỗi ANR trong BroadcastReceiver
Thời gian thực thi BroadcastReceiver bị hạn chế vì broadcast receiver được dùng để thực hiện các khối lượng công việc nhỏ, riêng biệt ở chế độ nền, chẳng hạn như lưu một chế độ cài đặt hoặc đăng ký một Notification. Vì vậy, giống như các phương thức khác được gọi trong luồng giao diện người dùng, ứng dụng phải tránh các thao tác hoặc hoạt động tính toán có thể diễn ra trong thời gian dài trong một broadcast receiver. Thay vì thực hiện các tác vụ diễn ra trong thời gian dài thông qua luồng giao diện người dùng, hãy thực hiện các tác vụ đó trong nền để thực thi sau. Hãy xem bài viết Tổng quan về hoạt động trong nền để biết thêm thông tin về các giải pháp khả thi.
Một vấn đề thường gặp khác với các đối tượng BroadcastReceiver xảy ra khi các đối tượng này thực thi quá thường xuyên. Việc thường xuyên thực thi trong nền có thể làm giảm dung lượng bộ nhớ dành cho các ứng dụng khác. Để biết thêm thông tin về cách bật và tắt các đối tượng BroadcastReceiver một cách hiệu quả, hãy xem bài viết Tổng quan về thông báo truyền tin.
Tăng cường khả năng phản hồi
Thông thường, người dùng sẽ cảm nhận được một ứng dụng đang chạy chậm nếu thời gian phản hồi vượt quá ngưỡng 100 đến 200 mili giây. Dưới đây là một số lưu ý khác để khiến người dùng cảm thấy có vẻ như ứng dụng của bạn phản hồi nhanh chóng:
Nếu ứng dụng của bạn đang hoạt động ở chế độ nền khi phản hồi hoạt động đầu vào của người dùng, hãy cho thấy rằng tiến trình đang được thực hiện, chẳng hạn như bằng một ProgressBar trong giao diện người dùng.
Riêng đối với trò chơi, hãy tính toán các bước trong một luồng worker.
Nếu ứng dụng của bạn có giai đoạn thiết lập ban đầu mất nhiều thời gian, hãy cân nhắc làm hiện màn hình chờ hoặc kết xuất khung hiển thị chính nhanh nhất có thể.
Cho người dùng biết rằng quá trình tải đang diễn ra và hiện thông tin theo cách không đồng bộ.
Trong cả hai trường hợp, bằng cách nào đó, bạn nên cho người dùng biết rằng tiến trình đang diễn ra để người dùng không thấy là ứng dụng bị treo.
Sử dụng các công cụ hỗ trợ hiệu suất như Perfetto và Trình phân tích CPU để xác định điểm tắc nghẽn ảnh hưởng đến khả năng phản hồi của ứng dụng.
Nội dung và mã mẫu trên trang này phải tuân thủ các giấy phép như mô tả trong phần Giấy phép nội dung. Java và OpenJDK là nhãn hiệu hoặc nhãn hiệu đã đăng ký của Oracle và/hoặc đơn vị liên kết của Oracle.
Cập nhật lần gần đây nhất: 2025-07-27 UTC.
[[["Dễ hiểu","easyToUnderstand","thumb-up"],["Giúp tôi giải quyết được vấn đề","solvedMyProblem","thumb-up"],["Khác","otherUp","thumb-up"]],[["Thiếu thông tin tôi cần","missingTheInformationINeed","thumb-down"],["Quá phức tạp/quá nhiều bước","tooComplicatedTooManySteps","thumb-down"],["Đã lỗi thời","outOfDate","thumb-down"],["Vấn đề về bản dịch","translationIssue","thumb-down"],["Vấn đề về mẫu/mã","samplesCodeIssue","thumb-down"],["Khác","otherDown","thumb-down"]],["Cập nhật lần gần đây nhất: 2025-07-27 UTC."],[],[],null,["# Keep your app responsive\n\n**Figure 1.** An ANR dialog displayed to the user.\n\nThis document describes how the Android system determines whether an app isn't\nresponding and shows how to keep your app responsive.\n\nNo matter how well-written your code is, it's possible for your app to still\nfeel sluggish, hang, freeze for significant periods, or take too long to process\ninput. If your app is in the foreground and is unresponsive, the user gets an\nApplication Not Responding (ANR) dialog, as shown in figure 1. The ANR dialog\nlets the user force quit the app. If the app isn't in the foreground, then it's\nsilently stopped. It's critical to design responsiveness into your app to\nminimize ANR dialogs.\n\nANR triggers\n------------\n\nGenerally, the system displays an ANR if an app can't respond to user input on\nthe main thread---also known as the UI thread---preventing the system from\nprocessing incoming user input events.\n\nFor example, an ANR can occur if an app performs a blocking I/O operation, such\nas network access, on the UI thread. Another example is when an app spends too\nmuch time building an elaborate in-memory structure or computing the next move\nin a game on the UI thread.\n\nIn Android, app responsiveness is monitored by the [`ActivityManager`](/reference/android/app/ActivityManager) and\n[`WindowManager`](/reference/android/view/WindowManager) system services. Android displays the ANR dialog for an app\nwhen it detects one of the following conditions:\n\n- No response to an input event---such as key press or screen tap events---within 5 seconds.\n- A [`BroadcastReceiver`](/reference/android/content/BroadcastReceiver) doesn't finish executing within 10 to 20 seconds, for foreground intents. For more information, see [Broadcast receiver timeout](/topic/performance/anrs/diagnose-and-fix-anrs#broadcast-receiver-anr).\n\nAvoid ANRs\n----------\n\nThe following are general tips to avoid ANRs. For more details about diagnosing\nand debugging different types of ANRs, see the other pages in this section.\n\n- Keep the main thread unblocked at all times, and use threads strategically.\n\n - Don't perform blocking or long-running operations on the app's main thread.\n Instead, create a worker thread and do most of the work there.\n\n - Try to minimize any lock contention between the main thread and other\n threads.\n\n - Minimize any non-UI related work on the main thread, such as when handling\n broadcasts or running services. Any method that runs in the UI thread must\n do as little work as possible on that thread. In particular, activities must\n do as little as possible to set up in key lifecycle methods, such as\n `onCreate()` and `onResume()`. See [Background work overview](/guide/background) for more\n information about available solutions for scheduling work on a background\n thread and communicating back with the UI.\n\n - Be careful when sharing thread pools between components. Don't use the same\n threads for potentially long-blocking operations and time-sensitive tasks\n such as broadcast receiving.\n\n | **Note:** Because such threading usually is accomplished at the class level, you can think of responsiveness as a class problem. Compare this with basic code performance, which is a method-level concern.\n- Keep app startup fast. Minimize slow or blocking operations in the app's\n startup code, such as methods run during dagger initialization.\n\n- If you're using `BroadcastReceiver`, consider running broadcast receivers in a\n non-main thread using [`Context.registerReceiver`](/reference/android/content/Context#registerReceiver(android.content.BroadcastReceiver,%20android.content.IntentFilter,%20java.lang.String,%20android.os.Handler,%20int)). For more information,\n see [ANRs in BroadcastReceiver](#anrs-in-broadcast-receiver).\n\n - If you use [`goAsync()`](/reference/android/content/BroadcastReceiver#goAsync()), make sure [`PendingResult.finish`](/reference/kotlin/android/content/BroadcastReceiver.PendingResult?#finish) is called quickly before the ANR timeout.\n\nANRs in BroadcastReceiver\n-------------------------\n\n`BroadcastReceiver` execution time is constrained because broadcast receivers\nare meant to do small, discrete amounts of work in the background, such as\nsaving a setting or registering a [`Notification`](/reference/android/app/Notification). So, as with other\nmethods called in the UI thread, apps must avoid potentially long-running\noperations or calculations in a broadcast receiver. Instead of performing\nlong-running tasks via the UI thread, perform them in the background for later\nexecution. See [Background work overview](/guide/background) for more information about possible\nsolutions.\n\nAnother common issue with `BroadcastReceiver` objects occurs when they execute\ntoo frequently. Frequent background execution can reduce the amount of memory\navailable to other apps. For more information about how to enable and disable\n`BroadcastReceiver` objects efficiently, see [Broadcasts overview](/guide/components/broadcasts).\n| **Tip:** You can use [`StrictMode`](/reference/android/os/StrictMode) to help find potentially lengthy operations such as network or database operations that you might accidentally be doing on your main thread.\n\nReinforce responsiveness\n------------------------\n\nGenerally, 100 to 200ms is the threshold beyond which users perceive slowness in\nan app. Here are additional tips for making your app seem responsive to users:\n\n- If your app is doing work in the background in response to user input, show\n that progress is being made, such as with a [`ProgressBar`](/reference/android/widget/ProgressBar) in your UI.\n\n- For games specifically, do calculations for moves in a worker thread.\n\n- If your app has a time-consuming initial setup phase, consider showing a\n [splash screen](/develop/ui/views/launch/splash-screen) or rendering the main view as quickly as possible.\n Indicate that loading is in progress and fill the information asynchronously.\n In either case, we recommend indicating somehow that progress is being made,\n so that the user doesn't perceive that the app is frozen.\n\n- Use performance tools such as [Perfetto](/topic/performance/tracing) and [CPU Profiler](/studio/profile/cpu-profiler) to\n determine bottlenecks in your app's responsiveness."]]