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.mzph.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;结尾部分的记忆优势被称为近因效应。这种效应反映…