Android如何监听anr,Android性能优化之ANR异常监测

前言

ANR是Application Not Responding的缩写,即应用程序无响应。简单来说,就是应用的界面突然卡住了,无法响应用户的操作如触摸事件等。

优化思路

8abce3ff4687

1 ANR执行流程

发生ANR

进程接收异常终止信号,开始写入进程ANR信息

弹出ANR提示框(Rom表现不一,有可能不弹)

2 如何解决ANR

解决ANR问题,首先要做的是找到问题,线下我们可以通过ADB命令导出ANR文件进行分析,线上我们可以使用FileObserver或ANR-WatchDog保存ANR堆栈信息,然后上传到服务器。

2.1导出ANR文件

ANR发生之后我们可以使用以下命令导出ANR文件:

adb pull data/anr/traces.txt 存储路径

或者

//生成

adb bugreport

//导出

adb pull 文件路径 存储路径

8abce3ff4687

生成bugreport

8abce3ff4687

导出bugreport

2.2 ANR文件分析

使用命令会导出一个zip压缩包,ANR文件在FS/data/anr目录下。

8abce3ff4687

ANR文件

我的实例是在MainActivity的第41行做了个Thread.sleep(20*1000)的操作。

8abce3ff4687

ANR文件分析

2.3 线上ANR监控方案

线上监控方案我们可以实现FileObserver去监听ANR目录的变化和使用ANR-WatchDod去监听并打印ANR堆栈信息。

FileObserver

注意事项:

FileOberver需要三种权限

FileOberver的startWatching、stopWatching都加锁,因此我们要避免在对象锁中实现,以免造成死锁。

public int[] startWatching(List files,

@NotifyEventType int mask, FileObserver observer) {

final int count = files.size();

final String[] paths = new String[count];

for (int i = 0; i < count; ++i) {

paths[i] = files.get(i).getAbsolutePath();

}

final int[] wfds = new int[count];

Arrays.fill(wfds, -1);

startWatching(m_fd, paths, mask, wfds);

final WeakReference fileObserverWeakReference = new WeakReference<>(observer);

synchronized (m_observers) {

for (int wfd : wfds) {

if (wfd >= 0) {

m_observers.put(wfd, fileObserverWeakReference);

}

}

}

return wfds;

}

使用方法:

@SuppressLint("NewApi")

fun startANRListener(){

val fileObserver = object :FileObserver(File("/data/anr/"), CLOSE_WRITE){

override fun onEvent(event: Int, path: String?) {

Log.d("ANRWatching", "/data/anr/$path")

}

}

fileObserver.startWatching()

}

ANR-WatchDog

Git地址:ANR-WatchDog

ANR-WatchDog是一个非侵入式的ANR监控组件。

使用步骤:

在app/build.gradle添加依赖

implementation 'com.github.anrwatchdog:anrwatchdog:1.4.0'

在application类的onCreate中使用,即可实现自动监测ANR。

class MyApplication: Application() {

override fun onCreate() {

super.onCreate()

ANRWatchDog().start();

}

}

ANR发生之后可直接在日志中查看堆栈信息:

8abce3ff4687

也可以在Application中监听ANR-WatchDog返回的错误日志。

class MyApplication : Application() {

override fun onCreate() {

super.onCreate()

BlockCanary.install(this, AppBlockCanaryContext()).start()

val anrWatchDog = ANRWatchDog()

anrWatchDog.setANRListener {

}

anrWatchDog.start()

}

}

原理

ANRWatchDog继承子Thread,所以它最重要的就是run方法。核心内容可以分为以下几点:

在run方法中实现无限循环

_tick自动加上5000毫秒并往Handler发消息

睡眠5000毫秒

如果5000毫秒之内主线程还没有处理Runnable,将_tick置0,则进入ANR异常。

public class ANRWatchDog extends Thread {

private static final int DEFAULT_ANR_TIMEOUT = 5000;

private final Handler _uiHandler = new Handler(Looper.getMainLooper());

private final int _timeoutInterval;

private volatile long _tick = 0;

private volatile boolean _reported = false;

private final Runnable _ticker = new Runnable() {

@Override public void run() {

// _tick = 0用于 第5步判断

_tick = 0;

_reported = false;

}

};

/**

* Constructs a watchdog that checks the ui thread every {@value #DEFAULT_ANR_TIMEOUT} milliseconds

*/

public ANRWatchDog() {

this(DEFAULT_ANR_TIMEOUT);

}

/**

* Constructs a watchdog that checks the ui thread every given interval

*

* @param timeoutInterval The interval, in milliseconds, between to checks of the UI thread.

* It is therefore the maximum time the UI may freeze before being reported as ANR.

*/

public ANRWatchDog(int timeoutInterval) {

super();

_timeoutInterval = timeoutInterval;

}

@SuppressWarnings("NonAtomicOperationOnVolatileField")

@Override

public void run() {

setName("|ANR-WatchDog|");

long interval = _timeoutInterval;

//1 无限循环

while (!isInterrupted()) {

boolean needPost = _tick == 0;

//2 _tick自增

_tick += interval;

if (needPost) {

//3 发送消息

_uiHandler.post(_ticker);

}

try {

//4 睡眠

Thread.sleep(interval);

} catch (InterruptedException e) {

_interruptionListener.onInterrupted(e);

return ;

}

//5 如果UI线程没有处理_ticker, 走下面代码块,进入ANR异常。

if (_tick != 0 && !_reported) {

//noinspection ConstantConditions

if (!_ignoreDebugger && (Debug.isDebuggerConnected() || Debug.waitingForDebugger())) {

Log.w("ANRWatchdog", "An ANR was detected but ignored because the debugger is connected (you can prevent this with setIgnoreDebugger(true))");

_reported = true;

continue ;

}

interval = _anrInterceptor.intercept(_tick);

if (interval > 0) {

continue;

}

final ANRError error;

if (_namePrefix != null) {

error = ANRError.New(_tick, _namePrefix, _logThreadsWithoutStackTrace);

} else {

error = ANRError.NewMainOnly(_tick);

}

_anrListener.onAppNotResponding(error);

interval = _timeoutInterval;

_reported = true;

}

}

}

}

总结

ANR异常我们可分为线上监测和线下监测两个方向

线上监测主要是利用FileObserver进行ANR目录文件变化监听,以ANR-WatchDog进行补充。

FileObserver在使用过程中应注意高版本程序不可用以及预防死锁出现。

线下监测主要是在报错之后利用ADB命令将错误的日志导出并找到错误的类进行分析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值