Android學習總結之ANR問題

一、ANR 基礎概念與核心原理(必考題)

1. 什么是 ANR?為什么會發生 ANR?

答案要點

  • 定義:ANR(Application Not Responding)即應用無響應,是 Android 系統檢測到主線程(UI 線程)長時間阻塞時觸發的機制,用戶會看到 “等待 / 關閉應用” 對話框18。
  • 根本原因:主線程被耗時操作(如 IO、網絡請求、復雜計算)阻塞,或因鎖競爭、CPU 資源不足導致無法及時處理輸入事件或系統回調911。
  • 系統檢測機制
    • 輸入事件:5 秒未處理(如點擊、滑動)513。
    • 廣播接收器:前臺廣播 10 秒、后臺廣播 60 秒未完成onReceive47。
    • 服務:前臺服務 20 秒、后臺服務 200 秒未完成onStartCommand等生命周期方法413。
    • 內容提供者:10 秒未完成query/insert等操作513。
2. 列舉 ANR 的四種場景及超時時間(高頻考點)

答案要點

場景超時時間觸發條件
輸入事件超時5 秒用戶交互(如點擊、滑動)未在 5 秒內處理完成513。
前臺廣播超時10 秒BroadcastReceiver.onReceive執行超過 10 秒(如Context.sendOrderedBroadcast)47。
后臺廣播超時60 秒后臺廣播(如Context.startBroadcast)未在 60 秒內完成413。
前臺服務超時20 秒Service.onStartCommand/onBind未在 20 秒內返回413。
后臺服務超時200 秒后臺服務執行超過 200 秒(Android 8.0+)413。
內容提供者超時10 秒ContentProviderquery/insert等方法未在 10 秒內完成513。

注意:不同 Android 版本可能略有差異,需強調常見標準值47。

二、ANR 日志分析與定位(技術難點)

1. 如何通過日志定位 ANR 原因?

答案要點

  • 日志獲取
    • 使用adb pull /data/anr/traces.txt導出 ANR 日志67。
    • 通過adb logcat -b events -s anr實時捕獲 ANR 信息6。
  • 關鍵字段解析
    • ANR in com.example.app:定位發生 ANR 的應用包名和組件(如 Activity)67。
    • Reason: Input dispatching timed out:明確 ANR 類型(輸入事件、廣播等)67。
    • 主線程堆棧
      "main" prio=5 tid=1 Blocked  
      at com.example.app.MainActivity.loadData(MainActivity.kt:45)  // 阻塞代碼行  
      - waiting to lock <0x123456> (a java.lang.Object) owned by thread=10  // 鎖競爭  
      
      ?
      • 分析state=S(阻塞狀態)、waiting to lock(鎖持有者)及具體代碼行號79。
    • 其他線程狀態
      "Thread-10" prio=5 tid=10 Holding lock  
      at com.example.app.DataManager.lockData(DataManager.kt:78)  // 持有鎖的線程  
      
      ?
      • 檢查是否有子線程長時間持有鎖或占用 CPU79。

面試技巧:結合日志示例說明分析步驟,強調從Reason→主線程堆棧→其他線程狀態的邏輯鏈67。

2. 如何區分 ANR 是應用自身問題還是系統資源不足?

答案要點

  • 應用自身問題
    • 主線程堆棧顯示耗時操作(如Thread.sleep、數據庫查詢)911。
    • 鎖競爭導致主線程等待(如synchronized塊未及時釋放鎖)79。
  • 系統資源不足
    • 日志中CPU usage顯示高負載(如user + kernel > 80%)713。
    • 內存不足導致頻繁 GC 或進程被回收913。
  • 工具輔助
    • 使用adb shell top -m 10 -s cpu查看 CPU 占用,定位高負載進程79。
    • 通過 Android Studio Profiler 分析主線程耗時函數111。

三、ANR 規避與優化(實戰重點)

1. 如何避免主線程阻塞?

答案要點

  • 耗時操作異步化
    • 使用Coroutine/Handler/WorkManager將網絡請求、文件讀寫等移至后臺線程110。
    • 示例:
      // 使用協程處理耗時任務  
      viewModelScope.launch {  val data = withContext(Dispatchers.IO) { fetchDataFromNetwork() }  withContext(Dispatchers.Main) { updateUI(data) }  
      }  
      
  • 優化布局與渲染
    • 減少布局嵌套,使用ViewStub延遲加載非必要視圖19。
    • 避免在onDraw中創建對象,防止內存抖動29。
  • 合理使用鎖
    • 縮小synchronized塊范圍,避免在鎖內執行耗時操作19。
    • 使用ReentrantLock替代synchronized,提高鎖競爭效率19。
2. BroadcastReceiver 導致 ANR 的原因及解決方案

答案要點

  • 原因
    • onReceive在主線程執行,若包含耗時操作(如網絡請求、數據庫寫入),超過 10 秒 / 60 秒觸發 ANR25。
    • 有序廣播未及時調用abortBroadcast(),導致后續 Receiver 阻塞79。
  • 解決方案
    • 耗時操作轉后臺:通過IntentService/WorkManager處理異步任務210。
      class MyBroadcastReceiver : BroadcastReceiver() {  override fun onReceive(context: Context, intent: Intent) {  context.startService(Intent(context, MyIntentService::class.java))  }  
      }  
      
    • 限制onReceive邏輯:僅解析 Intent 或啟動組件,避免復雜計算59。
3. Service 導致 ANR 的典型場景及優化

答案要點

  • 典型場景
    • 直接在Service.onStartCommand中執行文件下載、數據庫批量操作等耗時任務29。
    • 前臺服務未及時調用startForeground(),導致超時閾值按后臺服務處理413。
  • 優化方案
    • 使用JobIntentService(繼承自IntentService)自動處理異步任務并銷毀服務110。
    • 示例:
      class MyJobService : JobIntentService() {  override fun onHandleWork(intent: Intent) {  // 后臺線程執行耗時操作  doHeavyWork()  }  
      }  
      
    • 前臺服務需在 5 秒內調用startForeground(),避免超時413。

四、ANR 面試高頻問題與陷阱

1. 為什么 ANR 通常發生在主線程?子線程阻塞會觸發 ANR 嗎?

答案

  • 主線程職責:處理 UI 更新、輸入事件、系統回調(如 Activity 生命周期、廣播接收),任何阻塞都會導致界面無響應89。
  • 子線程阻塞:不會直接觸發 ANR,但可能通過以下方式間接導致:
    • 子線程持有鎖,主線程等待鎖釋放(鎖競爭)79。
    • 子線程占用大量 CPU 資源,導致主線程無法搶占時間片913。
2. 如何模擬 ANR?列舉至少兩種方法

答案

  • 輸入事件超時
    // 在Activity.onCreate中阻塞主線程  
    override fun onCreate(savedInstanceState: Bundle?) {  super.onCreate(savedInstanceState)  Thread.sleep(6000) // 超過5秒觸發ANR  
    }  
    
  • 廣播接收器超時
    class MyBroadcastReceiver : BroadcastReceiver() {  override fun onReceive(context: Context, intent: Intent) {  Thread.sleep(11000) // 前臺廣播超過10秒觸發ANR  }  
    }  
    
  • 服務超時
    class MyService : Service() {  override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {  Thread.sleep(21000) // 前臺服務超過20秒觸發ANR  return super.onStartCommand(intent, flags, startId)  }  
    }  
    
3. 如何監控線上 ANR?

答案要點

  • 工具推薦
    • 華為 AGC 性能管理:自動采集 ANR 日志,提供堆棧分析和系統資源狀態13。
    • BlockCanary:開源庫,監控主線程卡頓并輸出堆棧信息111。
    • StrictMode:開發階段檢測主線程耗時操作(如磁盤 I/O、網絡請求)111。
  • 實現自定義監控
    • 監聽系統SIGQUIT信號,解析/data/anr/traces.txt文件111。
    • 通過Looper.getMainLooper().setMessageLogging監控消息隊列延遲11。

擴展ANR日志使用

1. ANR 基礎信息
** ANR in com.example.app (com.example.app/.MainActivity)  
PID: 12345  // 進程ID  
Reason: Input dispatching timed out (Waiting to send non-key event because the touched window has not finished processing its input events)  
ANR Details:  All threads were suspended except the debugger worker thread!  Wait queue length: 1  Wait queue head age: 5001ms  // 超時時間,超過5秒觸發Input ANR  
  • 關鍵字段
    • Reason:明確 ANR 類型(Input/Service/Broadcast/Provider)。
    • Wait queue head age:阻塞持續時間,對應不同場景的超時閾值(見下文)。
2. 主線程(UI 線程)堆棧
"main" prio=5 tid=1 Blocked  | group="main" sCount=1 dsCount=0 obj=0x74a00000 self=0xabc123  | sysTid=12345 nice=0 cgrp=default sched=0/0 handle=0xdef456  | state=S schedstat=( 123456789 12345678 1234 ) utm=4 stm=6  at com.example.app.MainActivity.loadData(MainActivity.kt:45)  // 阻塞發生的代碼行  - waiting to lock <0x123456> (a java.lang.Object) owned by thread=10  // 等待的鎖對象  at android.app.ActivityThread.handleMessage(ActivityThread.java:1994)  at android.os.Handler.dispatchMessage(Handler.java:106)  at android.os.Looper.loop(Looper.java:164)  at android.app.ActivityThread.main(ActivityThread.java:6938)  
  • 分析重點
    • state=S:表示主線程處于阻塞(Sleep)狀態。
    • waiting to lock:若存在鎖競爭,顯示被哪個線程(如thread=10)持有鎖。
    • 代碼行號:直接定位到阻塞發生的具體方法(如MainActivity.loadData)。
3. 其他線程狀態
"Thread-10" prio=5 tid=10 Holding lock  | group="main" sCount=1 dsCount=0 obj=0x123456 self=0x ghi789  | sysTid=12346 nice=0 cgrp=default sched=0/0 handle=0x jkl012  | state=S schedstat=( 76543210 1234567 890 ) utm=2 stm=5  at com.example.app.DataManager.lockData(DataManager.kt:78)  // 持有鎖的線程代碼  - locked <0x123456> (a java.lang.Object)  

  • 若主線程因等待鎖而阻塞,需檢查其他線程是否長時間持有鎖(如耗時操作未釋放鎖)。

不同場景 ANR 的日志分析實戰

1. Input ANR:主線程阻塞在耗時操作
  • 日志特征
    • Reason包含Input dispatching timed out
    • 主線程堆棧顯示在執行耗時操作(如 IO、復雜計算、未異步處理的網絡請求)。
  • 示例分析
    // 主線程在執行文件讀取(耗時操作未異步化)  
    at com.example.app.MainActivity.loadLargeFile(MainActivity.kt:105)  
    at com.example.app.MainActivity.onCreate(MainActivity.kt:40)  
    
  • 優化方向:將耗時操作移至子線程(如Coroutine/AsyncTask/WorkManager)。
2. BroadcastReceiver ANR:onReceive 耗時過長
  • 日志特征
    • Reason包含Timeout during broadcast handling
    • 主線程堆棧顯示在BroadcastReceiver.onReceive中執行耗時操作(如數據庫寫入、網絡請求)。
  • 特殊場景
    • 有序廣播(Ordered Broadcast):若在onReceive中未及時調用abortBroadcast()或處理結果,可能導致后續 Receiver 阻塞。
    • 前臺廣播超時閾值 10 秒,后臺 60 秒,需通過android:processIntentService異步處理。
  • 示例日志
    "main" prio=5 tid=1 Blocked  
    at com.example.app.MyBroadcastReceiver.onReceive(MyBroadcastReceiver.kt:30)  // 耗時的網絡請求  
    
3. Service ANR:后臺任務未異步化
  • 日志特征
    • Reason包含Timeout executing service
    • 主線程堆棧顯示在Service.onStartCommand中執行耗時邏輯(如未使用IntentService或協程)。
  • 典型錯誤
    // 直接在Service主線程處理文件下載  
    at com.example.app.DownloadService.onStartCommand(DownloadService.kt:55)  
    
  • 優化方案:使用JobIntentServiceWorkManager處理異步任務。
4. 鎖競爭導致的 ANR
  • 日志特征
    • 主線程狀態為waiting to lock,指向某個被其他線程持有的鎖(如synchronized對象)。
    • 持有鎖的線程可能在執行耗時操作(如死鎖、長耗時同步塊)。
  • 示例分析
    // 主線程等待線程10釋放鎖  
    "main" waiting to lock <0x123456> (owned by thread=10)  
    "Thread-10" holding lock <0x123456> at com.example.app.DataManager.lockData(...)  
    
  • 解決方案:縮小同步塊范圍,避免在鎖內執行耗時操作。

ANR 日志分析的核心步驟(面試高頻考點)

  1. 定位 ANR 類型:通過Reason字段確定是 Input/Service/Broadcast 等類型。
  2. 提取主線程堆棧:找到阻塞發生的具體方法(關注代碼行號和鎖信息)。
  3. 檢查超時閾值:對比日志中的Wait queue head age是否超過對應場景的閾值(如 5 秒、10 秒)。
  4. 分析其他線程:查看是否有子線程持有鎖、長時間占用 CPU 或阻塞主線程。
  5. 結合代碼邏輯:確認阻塞是否由耗時操作(IO / 網絡 / 復雜 UI)、未異步化任務或鎖競爭導致。

實戰工具與技巧

  1. adb 命令輔助
    • adb shell dumpsys activity activities | grep mResumedActivity:查看當前卡頓的 Activity。
    • adb shell top -m 10 -s cpu:定位 CPU 占用高的進程,輔助判斷是否因 CPU 繁忙導致主線程阻塞。
  2. Android Studio Profiler
    • 通過 CPU Profiler 查看主線程在 ANR 前后的函數調用耗時,定位耗時方法。
  3. 避免 ANR 的最佳實踐
    • 主線程僅處理 UI 更新,耗時操作通過Coroutine/Handler/WorkManager異步化。
    • 限制BroadcastReceiver.onReceive執行時間(10 秒內結束,復雜邏輯啟動 Service)。
    • 避免在onCreate/onResume等生命周期中執行耗時初始化操作。

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/903089.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/903089.shtml
英文地址,請注明出處:http://en.pswp.cn/news/903089.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

視頻監控從安裝到優化的技術指南,視頻匯聚系統EasyCVR智能安防系統構建之道

在當今數字化安防時代&#xff0c;監控系統的安裝與配置對于保障各類場所的安全起著至關重要的作用。從前期規劃到實際安裝&#xff0c;再到后期的功能實現與維護&#xff0c;每一個環節都不容小覷。本文將詳細闡述監控安裝過程中的關鍵要點&#xff0c;并結合EasyCVR平臺功能&…

如何避免IDEA每次打開新項目都重復配置Maven?

每次打開新項目都要重新設置Maven路徑&#xff1f;每次導入工程都要手動調整settings.xml&#xff1f;如果你也受夠了IDEA這種“健忘”行為&#xff0c;那么這篇文章就是為你準備的&#xff01;今天我們就來徹底解決這個問題&#xff0c;讓IDEA記住你的Maven配置&#xff0c;一…

PostgesSQL外部數據封裝FDW

PostgesSQL外部數據封裝FDW 1. FDW外部數據配置&#xff08;單表&#xff09;1.1 遠端數據庫創建測試表1.2 安裝擴展postges\_fdw1.3 創建外部服務SERVER1.4 創建用戶映射USER MAPPING1.5 創建遠程表FOREIGN TABLE1.6 數據庫更新測試 2. FDW外部數據配置&#xff08;用戶&#…

策略模式(Strategy Pattern)詳解

文章目錄 1. 什么是策略模式&#xff1f;2. 為什么需要策略模式&#xff1f;3. 策略模式的核心概念3.1 策略&#xff08;Strategy&#xff09;3.2 具體策略&#xff08;Concrete Strategy&#xff09;3.3 上下文&#xff08;Context&#xff09; 4. 策略模式的結構5. 策略模式的…

在 Vue3 中封裝的 Axios 實例中,若需要為部分接口提供手動取消請求的功能

核心思路 封裝接口時返回 Promise 和 abort 方法&#xff1a; 為需要支持取消的接口返回一個對象&#xff0c;包含 promise 和 abort 方法&#xff0c;用戶可通過 abort 主動中斷請求。使用 AbortController 或 CancelToken&#xff1a; 推薦 AbortController&#xff08;瀏覽…

Flink介紹——實時計算核心論文之Dataflow論文詳解

引入 在過去的幾篇文章里&#xff0c;我們看到了大數據的流式處理系統是如何一步一步進化的。從最早出現的S4&#xff0c;到能夠做到“至少一次”處理的Storm&#xff0c;最后是能夠做到“正好一次”數據處理的MillWheel。我們會發現&#xff0c;這些流式處理框架&#xff0c;…

Python自動化解決滑塊驗證碼的最佳實踐

1. 引言&#xff1a;滑塊驗證碼的挑戰與自動化需求 滑塊驗證碼&#xff08;Slider CAPTCHA&#xff09;是當前互聯網廣泛使用的反爬機制之一&#xff0c;它要求用戶手動拖動滑塊到指定位置以完成驗證。這種驗證方式可以有效阻止簡單的自動化腳本&#xff0c;但對爬蟲開發者來說…

路由與OSPF學習

【路由是跨網段通訊的必要條件】 路由指的是在網絡中&#xff0c;數據包從源主機傳輸到目的主機的路徑選擇過程。 路由通常涉及以下幾個關鍵元素&#xff1a; 1.路由器&#xff1a;是一種網絡設備&#xff0c;負責將數據包從一個網絡傳輸到另一個網絡。路由器根據路由表來決定…

(done) 吳恩達版提示詞工程 5. 推理 (情緒分類,控制輸出格式,輸出 JSON,集成多個任務,文本主題推斷和索引,主題內容提醒)

url: https://www.bilibili.com/video/BV1Z14y1Z7LJ?spm_id_from333.788.videopod.episodes&vd_source7a1a0bc74158c6993c7355c5490fc600&p2 別人的筆記 url: https://zhuanlan.zhihu.com/p/626966526 5. 推理任務&#xff08;Inferring&#xff09; 這個視頻是關于…

MySQL VS SQL Server:優缺點全解析

數據庫選型、企業協作、技術生態、云數據庫 1.1 MySQL優缺點分析 優點 開源免費 社區版完全免費&#xff0c;適合預算有限的企業 允許修改源碼定制功能&#xff08;需遵守GPL協議&#xff09; 跨平臺兼容性 支持Windows/Linux/macOS&#xff0c;適配混合環境部署 云服務商…

Pycharm 代理配置

Pycharm 代理配置 文章目錄 Pycharm 代理配置1. 設置系統代理1.1 作用范圍1.2 使用場景1.3 設置步驟 2. 設置 python 運行/調試代理2.1 作用范圍2.2 使用場景2.3 設置步驟 Pycharm 工具作為一款強大的 IDE&#xff0c;其代理配置在實際開發中也是必不可少的&#xff0c;下面介紹…

maven打包時配置多環境參數

1. pom配置 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.…

國產三維CAD皇冠CAD在機械及汽車零部件設計建模教程:斜滑動軸承

在線解讀『斜滑動軸承』的三維建模流程&#xff0c;講解布爾運算、旋轉凸臺/基體、異型導向孔、裝飾螺紋線等操作技巧&#xff0c;一起來皇冠CAD&#xff08;CrownCAD&#xff09;直播間學習制作步驟吧&#xff01; 斜滑動軸承憑借其獨特的工作原理和廣泛的應用領域&#xff0c…

linux(操作系統概述和虛擬機的安裝)

1.操作系統 一、主流服務器操作系統 Windows server 市場地位&#xff1a;適合傳統企業&#xff08;主要以中小型企業、金融機構和教育機構為主&#xff09; 核心特點&#xff1a; 企業級功能&#xff1a;活動目錄、組策略、IIS/Web服務器、Exchange郵件服務 易用性&#xff1a…

鴻蒙生態新利器:華為ArkUI-X混合開發框架深度解析

鴻蒙生態新利器&#xff1a;華為ArkUI-X混合開發框架深度解析 作者&#xff1a;王老漢 | 鴻蒙生態開發者 | 2025年4月 &#x1f4e2; 前言&#xff1a;開發者們的新機遇 各位鴻蒙開發者朋友們&#xff0c;是否還在為多平臺開發重復造輪子而苦惱&#xff1f;今天給大家介紹一位…

數據結構初階:二叉樹(四)

概述&#xff1a;本篇博客主要介紹鏈式結構二叉樹的實現。 目錄 1.實現鏈式結構二叉樹 1.1 二叉樹的頭文件&#xff08;tree.h&#xff09; 1.2 創建二叉樹 1.3 前中后序遍歷 1.3.1 遍歷規則 1.3.1.1 前序遍歷代碼實現 1.3.1.2 中序遍歷代碼實現 1.3.1.3 后序遍歷代…

Electron Forge【實戰】桌面應用 —— AI聊天(下)

此為系列教程&#xff0c;需先完成 Electron Forge【實戰】桌面應用 —— AI聊天&#xff08;上&#xff09;Electron Forge【實戰】桌面應用 —— AI聊天&#xff08;中&#xff09; 會話列表按更新時間倒序加載 src/db.ts db.version(1).stores({// 主鍵為id&#xff0c;且…

[架構之美]Ubuntu源碼部署APISIX全流程詳解(含避坑指南)

[架構之美]Ubuntu源碼部署APISIX全流程詳解(含避坑指南) 一、離線安裝場景需求分析 1.1 典型應用場景 金融/政務內網環境生產環境安全合規要求邊緣計算節點部署1.2 離線安裝難點 #mermaid-svg-B25djI0XquaOb1HM {font-family:"trebuchet ms",verdana,arial,sans-s…

多頭注意力(Multi?Head Attention)

1. 多頭注意力&#xff08;Multi?Head Attention&#xff09;原理 設輸入序列表示為矩陣 X ∈ R B L d model X\in\mathbb{R}^{B\times L\times d_{\text{model}}} X∈RBLdmodel?&#xff0c;其中 B B B&#xff1a;批大小&#xff08;batch size&#xff09;&#xff0c…

系列位置效應——AI與思維模型【80】

一、定義 系列位置效應思維模型是指在一系列事物或信息的呈現過程中&#xff0c;人們對于處于系列開頭和結尾部分的項目的記憶效果優于中間部分項目的現象。具體而言&#xff0c;開頭部分的記憶優勢被稱為首因效應&#xff0c;結尾部分的記憶優勢被稱為近因效應。這種效應反映…