您的位置:首页 > 其它

BroadcastReceiver处理耗时操作

2012-07-23 14:38 330 查看
Long-Running Receivers and Services

So far, we have covered the happy path of broadcast receivers w here the execution of a

broadcast receiver is unlikely to take more than ten seconds.
As it turns out, the

problem space becomes a bit complicated if we want to perform tasks that take longer than ten seconds.

To understand why, let’s quickly review a few facts about broadcast receivers:

A broadcast receiver, like other components of an An droid process,

runs on the main thread.

Holding up the code in a broadcast receiver will hold up the main

thread and will result in ANR.

The time limit on a broadcast receiver is ten seconds compared to five

seconds for an activity. It is a touch of a reprieve, but the limit is still

there.

The process hosting the broadcast receiver will start and terminate

along with the broadcast receiver execution. Hence the process will

not stick around after the broadcast receiver’s onReceive() method

returns. Of course, this is assumi ng that the process contains only the

broadcast receiver. If the process contains other components, such as

activities or services, that are alr eady running, then the lifetime of the

process takes these component life cycles into account as well.

Unlike a service process, a broadcast receiver process will not get restarted.

If a broadcast receiver were to start a separate thread and return to

the main thread, Android will assume that the work is complete and

will shut down the process even if there are threads running, bringing

those threads to abrupt stop.

Android acquires a partial wake lock when invoking a broadcast

service and releases it when it re turns from the service in the main

thread. A wake lock is a mechanism and an API class available in the

SDK to keep the device from going to sleep or wake it up if it is already asleep.

Given these predicates, how can we ex ecute longer-running code in response to a

broadcast event?

Long-Running Broadcast Receiver Protocol

The answer lies in resolving the following:

We will clearly need a separate thread so that the main thread can get

back and avoid ANR messages.

To stop Android from killing the process and hence the worker thread,

we need to tell Android that this process contains a component, such

as a service, with a life cycle. So we need to create or start that

service. The service itself cannot directly do the work for more than

five seconds because that happens on the main thread, so the service

needs to start a worker thread and let the main thread go.

For the duration of the worker thread’s execution, we need to hold on

to the partial wake lock so that the device won’t go to sleep. A partial

wake lock will allow the device to run code without turning on the

screen and so on, which allows for longer battery life.

The partial wake lock must be obtained in the main line code of the

receiver; otherwise, it will be too late. For example, you cannot do this

in the service, because it may be too late between the startService()

being issued by the broadcast receiver and the onStartCommand() of a

service that begins execution.

Because we are creating a service, the service itself can be brought

down and brought back up because of low-memory conditions. If this

happens, we need to acquire the wake lock again.

When the worker thread started by the onStartCommand() method of

the service completes its work, it needs to tell the service to stop so

that it can be put to bed and not brought back to life by Android.

It is also possible that more than one broadcast event can occur.

Given that, we need to be cautious about how many worker threads

we need to spawn.

Given these facts, the recommended protocol for extending the life of a broadcast

receiver is as follows:

1. Get a (static) partial wake lock in the onReceive() method of the

broadcast receiver. The partial wake lock needs to be static to allow

communication between the broadcast receiver and the service. There

is no other way of passing a reference of the wake lock to the service,

as the service is invoked through a default constructor that takes no

parameters.

2. Start a local service so that the process won’t be killed.

CHAPTER 19: Broadcast Receivers and Long-Running Services 516

3. In the service, start a worker thread to do the work. Do not do the work

in the onStart() method of the service. If you do, you are basically

holding up the main thread again.

4. When the worker thread is done, tell the service to stop itself either

directly or through a handler.

5. Have the service turn off the static wake lock. To repeat, a static wake

lock is the only way to communicate between a service and its invoker,

in this case the broadcast service, because there is no way to pass a

wake lock reference to the service.

You can read the book for more info, the following is an example:

public abstract class ALongRunningNonStickyBroadcastService
extends IntentService
{
public static String tag = "ALongRunningBroadcastService";
protected abstract void

handleBroadcastIntent(Intent broadcastIntent);

public ALongRunningNonStickyBroadcastService(String name){
super(name);
}
/*
* This method can be invoked under two circumstances
* 1. When a broadcast receiver issues a "startService"
* 2. when android restarts it due to pending "startService" intents.
*
* In case 1, the broadcast receiver has already
* setup the "lightedgreenroom".
*
* In case 2, we need to do the same.
*/
@Override
public void onCreate()
{
super.onCreate();

//Set up the green room
//The setup is capable of getting called multiple times.
LightedGreenRoom.setup(this.getApplicationContext());

//It is possible that more than one service
//of this type is running.
//Knowing the number will allow us to clean up
//the locks in ondestroy.
LightedGreenRoom.s_registerClient();
}
@Override
public int onStartCommand(Intent intent, int flag, int startId)
{
//Call the IntentService "onstart"
super.onStart(intent, startId);

//Tell the green room there is a visitor
LightedGreenRoom.s_enter();

//mark this as non sticky
//Means: Don't restart the service if there are no
//pending intents.
return Service.START_NOT_STICKY;
}
/*
* Note that this method call runs
* in a secondary thread setup by the IntentService.
*
* Override this method from IntentService.
* Retrieve the original broadcast intent.
* Call the derived class to handle the broadcast intent.
* finally tell the lighted room that you are leaving.
* if this is the last visitor then the lock
* will be released.
*/
@Override
final protected void onHandleIntent(Intent intent)

{
try {
Intent broadcastIntent
= intent.getParcelableExtra("original_intent");
handleBroadcastIntent(broadcastIntent);
}
finally {
LightedGreenRoom.s_leave();
}
}
/*
* If Android reclaims this process,
* this method will release the lock
* irrespective of how many visitors there are.
*/
@Override
public void onDestroy() {
super.onDestroy();
LightedGreenRoom.s_unRegisterClient();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: