在项目中需要在后台进行一些IO工作,为了不阻塞UI线程,所以开启了一个Intent Service执行,然而在云测试中在几个机器上遇到了ANR。很疑惑。根据Intent Service源码,它并不会阻塞UI线程。
所以决定写个demo验证一下IntentService、Service、Thread与ANR的关系。
sleep 30秒的代码实现:
long endTime = System.currentTimeMillis() + 30 * 1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
如上图所示。写了6个代码段
执行结果分别如下:
- start IntentService,在onHandleIntent中wait 30秒。无ANR
05-19 11:01:19.009 28195-28195/com.example.testanr D/HHH: 开始执行intent service
05-19 11:01:19.046 28195-30213/com.example.testanr D/HHH: MyIntentService --> onHandleIntent, start
05-19 11:01:49.046 28195-30213/com.example.testanr D/HHH: MyIntentService --> onHandleIntent, end
可以看出30秒后正常退出。说明在IntentService中执行耗时操作并不会导致ANR
- for循环开启10个IntentService,在每个的onHandleIntent中wait 30秒。无ANR
05-19 11:02:15.107 28195-28195/com.example.testanr D/HHH: 开始执行intent service for循环10个
05-19 11:02:15.202 28195-31060/com.example.testanr D/HHH: MyIntentService --> onHandleIntent, start
05-19 11:02:45.202 28195-31060/com.example.testanr D/HHH: MyIntentService --> onHandleIntent, end
05-19 11:03:45.210 28195-31060/com.example.testanr D/HHH: MyIntentService --> onHandleIntent, start
05-19 11:04:15.210 28195-31060/com.example.testanr D/HHH: MyIntentService --> onHandleIntent, end
...分别顺序执行了10次
05-19 11:11:45.253 28195-31060/com.example.testanr D/HHH: MyIntentService --> onHandleIntent, start
05-19 11:12:15.253 28195-31060/com.example.testanr D/HHH: MyIntentService --> onHandleIntent, end
结果是10组 有序的这样开始-结束 开始-结束,所以IntentService是等前面的请求结束之后再执行下一个。 这个证实了 IntentService 采用单独的线程每次只从队列中拿出一个请求进行处理
- start Service,在onStartCommand中wait 30秒。有ANR
05-19 11:12:42.965 28195-28195/com.example.testanr D/HHH: 开始执行service
05-19 11:12:42.992 28195-28195/com.example.testanr D/HHH: MyService --> onHandleIntent, start
//20秒的时候发生ANR
05-19 11:13:12.993 28195-28195/com.example.testanr D/HHH: MyService --> onHandleIntent, end
说明Service里执行时间不能超过20秒,超过则会发生ANR
- start Thread,在run方法中wait 30秒。无ANR
05-19 11:13:21.067 28195-28195/com.example.testanr D/HHH: 开始执行my thread
05-19 11:13:21.071 28195-9066/com.example.testanr D/HHH: MyThread --> run, start: my thread
05-19 11:13:51.071 28195-9066/com.example.testanr D/HHH: MyThread --> run, end: my thread
在Tread中wait30秒,正常结束,不会ANR。
- for循环开启10个Thread,在每个run方法中wait 30秒。无ANR
05-19 11:13:56.574 28195-28195/com.example.testanr D/HHH: 开始执行my thread for循环10个
05-19 11:13:56.580 28195-9575/com.example.testanr D/HHH: MyThread --> run, start: thread3
05-19 11:13:56.581 28195-9573/com.example.testanr D/HHH: MyThread --> run, start: thread1
05-19 11:13:56.582 28195-9572/com.example.testanr D/HHH: MyThread --> run, start: thread0
05-19 11:13:56.593 28195-9574/com.example.testanr D/HHH: MyThread --> run, start: thread2
05-19 11:13:56.600 28195-9576/com.example.testanr D/HHH: MyThread --> run, start: thread4
05-19 11:13:56.610 28195-9582/com.example.testanr D/HHH: MyThread --> run, start: thread9
05-19 11:13:56.621 28195-9579/com.example.testanr D/HHH: MyThread --> run, start: thread6
05-19 11:13:56.623 28195-9578/com.example.testanr D/HHH: MyThread --> run, start: thread5
05-19 11:13:56.625 28195-9580/com.example.testanr D/HHH: MyThread --> run, start: thread7
05-19 11:13:56.626 28195-9581/com.example.testanr D/HHH: MyThread --> run, start: thread8
05-19 11:14:26.581 28195-9575/com.example.testanr D/HHH: MyThread --> run, end: thread3
05-19 11:14:26.583 28195-9573/com.example.testanr D/HHH: MyThread --> run, end: thread1
05-19 11:14:26.584 28195-9572/com.example.testanr D/HHH: MyThread --> run, end: thread0
05-19 11:14:26.593 28195-9574/com.example.testanr D/HHH: MyThread --> run, end: thread2
05-19 11:14:26.601 28195-9576/com.example.testanr D/HHH: MyThread --> run, end: thread4
05-19 11:14:26.615 28195-9582/com.example.testanr D/HHH: MyThread --> run, end: thread9
05-19 11:14:26.621 28195-9579/com.example.testanr D/HHH: MyThread --> run, end: thread6
05-19 11:14:26.624 28195-9578/com.example.testanr D/HHH: MyThread --> run, end: thread5
05-19 11:14:26.624 28195-9580/com.example.testanr D/HHH: MyThread --> run, end: thread7
05-19 11:14:26.626 28195-9581/com.example.testanr D/HHH: MyThread --> run, end: thread8
可以看出是无序同时开启的。
- for循环开启10000个Thread,在每个run方法中wait 30秒。OOM崩溃
大约开到2000个的时候OOM崩溃了。
通过源码可以分析出IntentService为什么可以执行耗时任务。一个IntentService,内部就创建了一个线程,通过Android提供的 Handler Message Looper,这些消息处理的类 构成了一个消息处理的模型。所以IntentService 的onHandleIntent 这个方法其实是在IntentService 中开辟的一个子线程中处理的。
理论上IntentService里执行耗时任务不会ANR,但是如果这个任务涉及到IO或者资源之类的,会导致ANR。