您的位置:首页 > 移动开发 > Objective-C

BroadcastReceiver的生命周期——从程序的一个bug说起

2011-01-11 16:29 288 查看
前几天遇到了这样一个问题。程序本身定义并注册了一个BroadcastReceiver用来响应某种广播消息,BroadcastReceiver收到消息后需要做一系列的处理,其中包括了比较费时的网络查询操作。于是问题出现了:当手机处于home screen时,BroadcastReceiver收到消息并开始处理,而此时点击该应用程序的图标并试图进入该程序时,会出现ANR错误。这是怎么回事?

经过试验,我发现当系统处于待机状态时,BroadcastReceiver收到消息并开始调用onReceive(Context, Intent)函数时,是运行在进程的主线程中。因此当点击应用程序图标试图启动程序时,由于onReceive(Context, Intent)函数还没有完成,因此只有等待。而Android系统本身会在程序响应超时时弹出ANR错误。

那么我们把这些耗时的处理操作单开一个线程运行,会不会解决这个问题呢?答案是否定的。虽然我在试验中确实发现这样做能让程序正常运行,而且没有ANR错误报出。但是这样方法是错误的。在Android API中关于BroadcastReceiver类生命周期的说明中有这么几段话:

A BroadcastReceiver object is only valid for the duration of the call to
onReceive(Context, Intent)
. Once your code returns from this function, the system considers the object to be finished and no longer active.

(一个BroadcastReceiver对象只在调用onReceive(Context, Intent)期间有效。一旦从该函数返回,系统会认为该对象已经完成,不再活跃。)

This has important repercussions to what you can do in an
onReceive(Context, Intent)
implementation: anything that requires asynchronous operation is not available, because you will need to return from the function to handle the asynchronous operation, but at that point the BroadcastReceiver is no longer active and thus the system is free to kill its process before the asynchronous operation completes.

(这会对你能在onReceive(Context, Intent)函数中能做什么有非常大的影响:任何异步操作都是不可用的。因为你需要从该函数返回去进行异步操作,但此时BroadcastReceiver已经不再活跃,因此系统可以在异步操作完成之前杀掉它的进程。)

In particular, you may not show a dialog or bind to a service from within a BroadcastReceiver. For the former, you should instead use the
NotificationManager
API. For the latter, you can use
Context.startService()
to send a command to the service.

(尤其是你不能在BroadcastReceiver显示一个对话框或者bind到一个service。对与前者,你应该使用NotificationManager API,而后者,你可以使用Context.startService()去发送一个命令给service。)

这就解释了为什么把这些耗时的处理操作单开一个线程运行是错误的。Android系统并不能保证该操作能够完成。其实正确的做法是使用Context.startService()去发送一个命令给service,让service去做这件事。实际上,我在修改该处代码时使用的是IntentService。根据Android API的说明,IntentService就是一个用于处理异步请求的Service类。Clients通过startService(Intent)方法发送请求(实际是Intent),IntentService会根据需要启动,在工作线程中按序处理到达的请求,当所有请求都完成之后,自动停止服务。由于所有的请求都是在一个线程中按序处理,因此后来的请求需要等待。因此IntentService的使用还是有局限性的。但是在我的程序中,因为请求实际上基本上间隔都比较长,因此,IntentService对于这种情况就已经足够了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐