`

android ANR错误时什么及如何预防

阅读更多
到底Android ANR是什么呢? 其实ANR就是Application Not Responding的全称,当某个应用处于长期假死状态时Android系统会弹出一个窗口上面写道,XXX is not responding给出两个按钮一个为force close一个为wait。可能会存在这样的情况,你写的代码通过了世界上所有的性能测试,但当用户尝试使用你的应用程序时,仍然让用户感到不爽。应用程序响应不够灵敏的地方包括——反映迟钝,挂起或冻结很长时间,或者需要花费很长的时间来处理输入。在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应用程序无响应(ANR:Application Not Responding)对话框。用户可以选择让程序继续运行,但是,他们在使用你的应用程序时,并不希望每次都要处理这个对话框。因此,在程序里对响应性能的设计很重要,这样,系统不会显示ANR给用户。一般说来,如果应用程序不能响应用户输入的话,系统会显示一个ANR。例如,一个应用程序阻塞在一些I/O操作上(通常是网络访问),这时,应用程序的主线程就不能再处理用户的输入事件。经过一定的时间后,系统认为应用程序已经挂起,并显示ANR来让用户选择杀死应用程序。相似地,如果你的应用程序花费太多的时间来构建详细的内存结构,或者也许是在游戏里花费太多时间来计算下一步移动,这时,系统会认为你的应用程序已经挂起。因此,确保这些计算是高效的往往很重要,但即使是最高效的代码仍然需要花费时间来运行。在这两种情况下,解决的方法通常是创建一个子线程,然后在线程里做你的大部分工作。这能让主线程(驱动UI事件循环)保持运行,并阻止系统认为你的代码已经冻结。因为这些线程通常是在类级别上完成的,因此,你可以认为响应性能问题是一个类的问题。(与基本性能相比而言,基本性能问题认为是方法级别的问题) 1 什么引发了ANR?在Android里,应用程序的响应性是由Activity Manager和Window Manager系统服务监视的。当它监测到以下情况中的一个时,Android就会针对特定的应用程序显示ANR:在5秒内没有响应输入的事件(例如,按键按下,屏幕触摸) BroadcastReceiver在10秒内没有执行完毕 2 如何避免ANR?考虑上面的ANR定义,让我们来研究一下为什么它会在Android应用程序里发生和如何最佳构建应用程序来避免ANR。 Android应用程序通常是运行在一个单独的线程(例如,main)里。这意味着你的应用程序所做的事情如果在主线程里占用了太长的时间的话,就会引发ANR对话框,因为你的应用程序并没有给自己机会来处理输入事件或者Intent广播。因此,运行在主线程里的任何方法都尽可能少做事情。特别是,Activity应该在它的关键生命周期方法(如onCreate()和onResume())里尽可能少的去做创建操作。潜在的耗时操作,例如网络或数据库操作,或者高耗时的计算如改变位图尺寸,应该在子线程里(或者以数据库操作为例,通过异步请求的方式)来完成。然而,不是说你的主线程阻塞在那里等待子线程的完成——也不是调用Thread.wait()或是Thread.sleep()。替代的方法是,主线程应该为子线程提供一个Handler,以便完成时能够提交给主线程。以这种方式设计你的应用程序,将能保证你的主线程保持对输入的响应性并能避免由于5秒输入事件的超时引发的ANR对话框。这种做法应该在其它显示UI的线程里效仿,因为它们都受相同的超时影响。 IntentReceiver执行时间的特殊限制意味着它应该做:在后台里做小的、琐碎的工作如保存设定或者注册一个Notification。和在主线程里调用的其它方法一样,应用程序应该避免在BroadcastReceiver里做耗时的操作或计算。但不再是在子线程里做这些任务(因为BroadcastReceiver的生命周期短),替代的是,如果响应Intent广播需要执行一个耗时的动作的话,应用程序应该启动一个Service。顺便提及一句,你也应该避免在Intent Receiver里启动一个Activity,因为它会创建一个新的画面,并从当前用户正在运行的程序上抢夺焦点。如果你的应用程序在响应Intent广播时需要向用户展示什么,你应该使用Notification Manager来实现。 3)增强响应灵敏性一般来说,在应用程序里,100到200ms是用户能感知阻滞的时间阈值。因此,这里有一些额外的技巧来避免ANR,并有助于让你的应用程序看起来有响应性。如果你的应用程序为响应用户输入正在后台工作的话,可以显示工作的进度(ProgressBar和ProgressDialog对这种情况来说很有用)。特别是游戏,在子线程里做移动的计算。如果你的应用程序有一个耗时的初始化过程的话,考虑可以显示一个Splash Screen或者快速显示主画面并异步来填充这些信息。在这两种情况下,你都应该显示正在进行的进度,以免用户认为应用程序被冻结了。是使用默认的加载模式。 android 线程间的通信 andriod提供了 Handler 和 Looper 来满足线程间的通信。例如一个子线程从网络上下载了一副图片,当它下载完成后会发送消息给主线程,这个消息是通过绑定在主线程的Handler来传递的。在 Android,这里的线程分为有消息循环的线程和没有消息循环的线程,有消息循环的线程一般都会有一个Looper,这个事android的新 概念。我们的主线程(UI线程)就是一个消息循环的线程。针对这种消息循环的机制,我们引入一个新的机制Handle,我们有消息循环,就要往消息循环里 面发送相应的消息,自定义消息一般都会有自己对应的处理,消息的发送和清除,消息的的处理,把这些都封装在Handle里面,注意Handle只是针对那 些有Looper的线程,不管是UI线程还是子线程,只要你有Looper,我就可以往你的消息队列里面添加东西,并做相应的处理。 但是这里还有一点,就是只要是关于UI相关的东西,就不能放在子线程中,因为子线程是不能操作UI的,只能进行数据、系统等其他非UI的操作。  在Android,这里的线程分为有消息循环的线程和没有消息循环的线程,有消息循环的线程一般都会有一个Looper,这个是android 的新概念。我们的主线程(UI线程)就是一个消息循环的线程。针对这种消息循环的机制,我们引入一个新的机制Handler,我们有消息循环,就要往消息循环里面发送相应的消息,自定义消息一般都会有自己对应的处理,消息的发送和清除,把这些都封装在Handler里面,注意Handler只是针对那 些有Looper的线程,不管是UI线程还是子线程,只要你有Looper,我就可以往你的消息队列里面添加东西,并做相应的处理。但是这里还有一点,就是只要是关于UI相关的东西,就不能放在子线程中,因为子线程是不能操作UI的,只能进行数据、系统等其他非UI的操作。一个Handler的创建它就会被绑定到这个线程的消息队列中,如果是在主线程创建的,那就不需要写代码来创建消息队列了,默认的消息队列会在主线程被创建。但是如果是在子线程的话,就必须在创建Handler之前先初始化线程的消息队列。
package com.magus.handler;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {
	private Handler mainHandler;
	private Handler childHandler;
	private TextView tv;
	private Button btn;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		tv = (TextView) findViewById(R.id.tv);
		btn = (Button) findViewById(R.id.btn);

		mainHandler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				// 接收子线程的消息
				tv.setText((String) msg.obj);
				super.handleMessage(msg);
			}
		};

		new ChildThread().start();

		btn.setOnClickListener(new OnClickListener() {

			public void onClick(View v) {
				if (childHandler != null) {
					// 发送消息给子线程
					Message childMsg = childHandler.obtainMessage();
					childMsg.obj = "笨蛋子线程";
					childHandler.sendMessage(childMsg);
				}

			}
		});
	}

	class ChildThread extends Thread {
		@Override
		public void run() {
			// 初始化消息循环队列,需要在Handler创建之前
			Looper.prepare();
			childHandler = new Handler() {
				@Override
				public void handleMessage(Message msg) {
					try {
						sleep(10000);

						Message toMainMessage = mainHandler.obtainMessage();
						toMainMessage.obj = "傻蛋UI线程" + "====="
								+ (String) msg.obj;
						mainHandler.sendMessage(toMainMessage);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}

				}
			};
			// 启动子线程消息循环队列
			Looper.loop();
		}
	}
}

分享到:
评论
1 楼 hualikejava 2012-07-12  
好文,希望楼主排版下。这看的太累了。

相关推荐

    Android-ANR-WatchDog一个用于检测AndroidANR(应用不响应)的watchdog

    `Android-ANR-WatchDog`是一个专门为解决这个问题而设计的开源工具,它能够帮助开发者监控并处理ANR错误,从而提高应用的稳定性和用户体验。 `Android-ANR-WatchDog`的工作原理是通过创建一个后台线程,该线程不断...

    android anr

    ANR错误通常发生在以下几种情况: 1. **UI线程阻塞**:主线程负责处理用户交互,如果在此线程中执行了耗时操作(如网络请求、大量计算或数据库操作),将导致UI无法更新,进而引发ANR。 2. **BroadcastReceiver超时*...

    android7 关闭ANR对话框代码

    在Android系统中,ANR(Application Not Responding)是一个常见的问题,它表示应用程序无响应,通常出现在用户界面长时间无法交互时。在Android 7.0版本中,框架引入了一种新特性,即自动关闭ANR对话框,并允许...

    如何分析及避免Android ANR问题.pdf

    在Android 7.0及以上版本,AMS会对前台服务的启动和前台服务的调用状态进行更严格的监测,如未在指定时间内完成操作,也会触发ANR。 在ANR发生时,AMS的appNotResponding接口会收集并输出相关的日志信息,包括...

    Android异常捕获demo(可以捕获ANR+UncaughtExceptionHandler)

    ANR是Android系统向用户报告应用无响应时显示的错误对话框。当应用主线程在5秒内无法完成输入事件(如点击按钮)或10秒内无法完成广播接收时,系统会触发ANR。这通常意味着应用可能陷入了死循环或者执行了耗时的...

    ANR代码流程分析.doc.tar.gz_ANR分析_android_anr代码_shp

    当ANR发生时,Android系统会记录一个ANR错误报告,并将其保存在/data/anr/traces.txt文件中,开发者可以从中获取到发生ANR时的堆栈跟踪信息。 分析ANR代码流程,首先要理解Android系统如何检测和处理ANR。在系统...

    android anr分析.docx

    ANR(Application Not Responding)是 Android 中的一个错误状态,当应用程序在 5 秒内没有响应输入事件或 BroadcastReceiver 在 10 秒内没有执行完毕时,Android 就会针对特定的应用程序显示 ANR 对话框。...

    防止ANR错误HandlerThread多线程解决耗时操作MyProject.zip

    在“防止ANR错误HandlerThread多线程解决耗时操作MyProject.zip”中,开发者可以深入研究源码,了解如何在实际项目中应用HandlerThread来避免ANR错误。同时,这个项目也提醒我们,良好的多线程管理是提升Android应用...

    ANR-WatchDog:一个简单的看门狗,可检测到Android ANR(应用程序无响应)错误并引发有意义的异常

    目录 阅读ANRError异常报告配置超时(ANR的最小挂起时间) 调试器在ANR回调上过滤报告看门狗线程捐 为什么存在目前,Android应用程序无法捕获和报告ANR错误。 如果您的应用程序不在Play商店中(要么是因为您仍在开发...

    安卓日志分析崩溃拦截相关-防止应用程序奔溃抛出错误异常防止应用程序anr.rar

    "安卓日志分析崩溃拦截相关-防止应用程序奔溃抛出错误异常防止应用程序anr.rar"这个资源包聚焦于一个核心问题:如何避免应用程序出现异常崩溃和ANR(Application Not Responding)错误。下面将详细解释相关知识点。 ...

    浅谈Android ANR在线监控原理

    ANR是一种常见的Android应用程序错误,发生在应用程序线程中执行时间过长,导致系统无法响应用户操作时。 在Android系统中,Watchdog是用来监测关键服务是否发生了死锁的机制。如果发生了死锁,Watchdog就会kill...

    ANR的监测与定位Demo

    ANR,全称为"Application Not Responding",是Android系统中用于表示应用程序无响应的错误提示。当一个Android应用的主线程在5秒内没有处理完事件(如UI更新、用户输入等)或者BroadcastReceiver在10秒内没有完成...

    android常见错误集

    在Android开发过程中,遇到各种错误是常有的事。这些错误可能是由于编程语法错误、API使用不当、资源管理问题或者是系统兼容性等因素导致的。本文将根据"android常见错误集"这个主题,结合压缩包中的"android常见...

    ANR-WatchDog,安卓系统.zip

    在Android操作系统中,当一个应用执行主线程上的操作超过5秒钟而未给出响应时,系统会向用户显示ANR对话框,提示应用未响应,用户体验严重下降。ANR-WatchDog就像是一个守护进程,持续关注应用的运行状态,一旦发现...

    ANR软件.rarANR软件.rar

    ANR(Application Not Responding)在Android系统中是一个常见的错误提示,意味着某个应用程序无响应,导致用户界面无法正常交互。ANR软件可能是针对这一问题的一种解决方案或者分析工具,旨在帮助开发者诊断和解决...

    ANR各种日志.rar

    如果超时,系统会记录一个ANR错误。开发者应检查广播接收器的代码,确保其尽可能地快速执行,并避免在主线程中进行耗时操作。如果确实有耗时任务,可以考虑使用IntentService或Worker线程来处理。 2. **System ...

    Android应用开发常见错误与对策

    四、Android 开发常见错误及对策 1. Adb连接异常 2. xml资源错误汇总 3. ANR(界面无响应) 4. 权限控制 5. 签名问题 6. 多国语言支持 7. 内存泄露和溢出 五、Android开发文化探讨 1. Android Design 文化 2. 做一个...

    Android NDK开发Crash错误定位

    而ANR错误通常在应用没有在规定时间内响应用户操作时触发,这时系统会在/data/anr/目录下生成traces.txt文件,记录ANR错误的相关信息。 对于涉及NDK的闪退问题,由于涉及到本地代码的执行,通常更难定位。本地代码...

    filemanager ANR log

    ANR错误通常在Android系统中发生,当用户界面线程被阻塞且无法在特定时间内响应用户交互时,系统会记录这种日志。 【描述】:“file Manager anr log ,it is lead by make source filemanger.” 这句话表明ANR问题...

    anr.rar_ANR

    在Android开发中,ANR是一个常见错误,当应用程序在主线程上执行了阻塞操作,导致用户界面无法响应超过5秒时,系统会抛出这个错误。然而,描述中提到的是"安然企业网站源码",这似乎与Android的ANR问题无关,而是...

Global site tag (gtag.js) - Google Analytics