赞
踩
描述:UI线程如果停止响应太长的时间, “Application Not Responding” (ANR) 就被触发。
触发:以下两个条件,任意各一个都会导致ANR
Strict mode
,可以找到主线程中意外的I/O操作。可以在Application或Activity中使用。一般推荐在Application级就使用。/data/anr/traces.txt
/data/anr/anr_*
adb bugreport
获取bug reports,或者从设备的开发者选项中获取。耗时计算:确定主线程中超过5秒操作的可疑代码,尝试重现ANR。Traceview timeline 可以直观的显示很忙的主线程操作。
AsyncTask
、Thread
、线程池等方式来实现,保证主线程的交互响应。示例代码,修改前:
@Override
public void onClick(View view) {
// 耗时很长的冒泡排序
BubbleSort.sort(data);
}
示例代码,修改后:
@Override
public void onClick(View view) {
// 将长耗时任务放在工作线程(子线程)中
new AsyncTask<Integer[], Integer, Long>() {
@Override
protected Long doInBackground(Integer[]... params) {
BubbleSort.sort(params[0]);
}
}.execute(data);
}
IO操作:推荐将IO操作放到子线程中,就像上一条一样。
锁竞争:如果子线程对某资源加锁,而主线程同样需要这个资源,ANR就可能会发生。
Monitor
或Wait
。查看trace file示例,也显示了资源锁竞争的问题:
AsyncTask #2” prio=5 tid=18 Runnable
| group=”main” sCount=0 dsCount=0 obj=0x12c333a0 self=0x94c87100
| sysTid=25287 nice=10 cgrp=default sched=0/0 handle=0x94b80920
| state=R schedstat=( 0 0 0 ) utm=757 stm=0 core=3 HZ=100
| stack=0x94a7e000-0x94a80000 stackSize=1038KB > | held mutexes= “mutator lock”(shared held)
at com.android.developer.anrsample.BubbleSort.sort(BubbleSort.java:8)
at com.android.developer.anrsample.MainActivity$LockTask.doInBackground(MainActivity.java:147)locked <0x083105ee> (a java.lang.Boolean)
at com.android.developer.anrsample.MainActivityLockTask.doInBackground(MainActivity.java:135)atandroid.os.AsyncTask 2.call(AsyncTask.java:305)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTaskSerialExecutor 1.run(AsyncTask.java:243)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
示例代码,修改前:
``` @Override public void onClick(View v) { // 子线程在lockedResource上持有锁 new LockTask().execute(data); synchronized (lockedResource) { // 主线程在这里需求lockedResource // 但必须等待子线程结束... } } public class LockTask extends AsyncTask<Integer[], Integer, Long> { @Override protected Long doInBackground(Integer[]... params) { synchronized (lockedResource) { // This is a long-running operation, which makes // the lock last for a long time BubbleSort.sort(params[0]); } } } ```
示例代码,修改后:
``` @Override public void onClick(View v) { WaitTask waitTask = new WaitTask(); synchronized (waitTask) { try { waitTask.execute(data); // 等待子线程的通知 waitTask.wait(); } catch (InterruptedException e) {} } } class WaitTask extends AsyncTask<Integer[], Integer, Long>{ @Override protected Long doInBackground(Integer[]... params) { synchronized (this) { BubbleSort.sort(params[0]); // 完成,通知主线程 notify(); } } } ```
Semaphore
信号标Deadlocks
慢广播:如果花费太长的时间用来处理广播消息时,会出现ANR。
onReceive()
执行时间太长。So不要在这个方法中执行耗时操作。goAsync()
,但没有调用PendingResult#finish()
IntentService
中去执行。onReceive()
示例代码,修改前:
@Override
public void onReceive(Context context, Intent intent) {
// 长耗时
BubbleSort.sort(data);
}
onReceive()
示例代码,修改后:
@Override
public void onReceive(Context context, Intent intent) {
// The task now runs on a worker thread.
Intent intentService = new Intent(context, MyIntentService.class);
context.startService(intentService);
}
public class MyIntentService extends IntentService {
@Override
protected void onHandleIntent(@Nullable Intent intent) {
BubbleSort.sort(data);
}
}
广播接收器可以通过goAsync
给系统发送一个请求更多时间来处理消息的信号,但在处理完成后,应该调用PendingResult#finish()
:
final PendingResult pendingResult = goAsync();
new AsyncTask<Integer[], Integer, Long>() {
@Override
protected Long doInBackground(Integer[]... params) {
// This is a long-running operation
BubbleSort.sort(params[0]);
pendingResult.finish();
}
}.execute(data);
请注意,只能在主线程中使用。如果将这段代码放到子线程中,ANR问题仍会出现。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。