0

I've a Broadcast Receiver into my application that waits for the screen to go on/off. What I want to do is:

public void onReceive(Context context, Intent intent) {
    if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
        pause some seconds...
        ...do something
    }
}

How can I stop the current thread into the onReceive method?

user1071138
  • 656
  • 3
  • 12
  • 30
  • It depends a bit on what you want to do after the screen goes off. Do you want to be _sure_ that "do something" will really happen after "some seconds" of _wall time_, or is it something else you have on your mind? – class stacker Apr 16 '13 at 13:15
  • Actually, I've something else in my mind: I want that the action performed on screenOff/screenOn is performed ONLY if the screen is blanked for more than ten seconds – user1071138 Apr 16 '13 at 13:29
  • Thanks for the clarification. I made a suggestion. – class stacker Apr 16 '13 at 13:58

3 Answers3

5

You can't and you shouldn't pause the BrodcastReceiver neither postDelayed to a Handler();

You shouldn't stop it because that thread needs to do other stuff, so don't block it because it's a bad design.

and you can't postDelay because from the docs:

Once you return from onReceive(), the BroadcastReceiver is no longer active, and its hosting process is only as important as any other application components that are running in it. This is especially important because if that process was only hosting the BroadcastReceiver (a common case for applications that the user has never or not recently interacted with), then upon returning from onReceive() the system will consider its process to be empty and aggressively kill it so that resources are available for other more important processes.

that means that the moment it returns from onReceive() all this will likely be killed very fast.

If you want something to happen some time after the broadcast you can start a service, and that service wait the amount of time, or if the amount of time you want to wait is longer than a few seconds, you should just put the launch of this service in the AlarmManager and let the AlarmManager launch the service for you.

Budius
  • 39,391
  • 16
  • 102
  • 144
  • This is correct. You must not perform long running operations in the onReceive(). There is a timeout of 10 seconds, after which the system may deem the thread to be blocked and kill it. – NickT Apr 16 '13 at 13:19
3

As per our short clarification, I suggest than in onReceive() you use the AlarmManager with set(RTC, System.currentTimeMillis()+10000, thePendingIntentToNotifyYou). This way, you'll be informed after ten seconds unless the device goes to sleep. (Use RTC_WAKEUP otherwise.)

Via your broadcast receivers, you'll also be informed about the screen being turned off and on (you'll need to listen for that as well to stop the timer if you don't do it already) and will have to maintain a small state machine so as to know whether the condition you're looking for (screen off for ten seconds) holds upon triggering of thePendingIntentToNotifyYou.

class stacker
  • 5,357
  • 2
  • 32
  • 65
  • @user1071138 How did you implement it? – class stacker Apr 20 '13 at 08:06
  • Into onReceive method: if(intent.getAction().equals(Intent.ACTION_SCREEN_OFF)){ wasScreenOn = false; handler.postDelayed(new Runnable(){ @Override public void run(){ if(!wasScreenOn){ do something... hasStopped=true; } }},10000); }else if(intent.getAction().equals(Intent.ACTION_SCREEN_ON)){ wasScreenOn = true; if(hasStopped){ do something... hasStopped=false; } } – user1071138 Apr 21 '13 at 17:26
  • @user1071138 Judging from the very short code snippet, this will not work as you expect if the screen is shortly turned on and immediately turned off again during the ten seconds you want to monitor. – class stacker Apr 22 '13 at 05:52
  • yes, in the case you mention it counts 10 seconds since the first time the screen is blanked...so, if during this time the screen is on and then off again, the first counter does not restart itself...fortunately, this behaviour does not worry me, because I just want to stop actions due to the automatic screen off (which I suppose t>10s)). Anyway, thanks for your suggestions! – user1071138 Apr 22 '13 at 14:46
  • In your opinion, can this issue be solved by adding: handler.removeCallbacksAndMessages(null); into the second if, so that the handler stops itself if the screen is on again? – user1071138 Apr 24 '13 at 12:06
  • @user1071138 If that's suddenly becoming important, you should now switch to an `AlarmManager` based solution, because yours is not guaranteed to work anyway. With your implementation, the device may well go to sleep during the ten seconds, and you'll only be informed after it wakes up again, for whatever reason. – class stacker Apr 24 '13 at 12:12
-1

use Handler.postDelayed method.

So your code will be something like this

Handler h = new Handler();
public void onReceive(Context context, Intent intent) {
    if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
        h.postDelayed(new Runnable(){
             public void run(){
                    // do something
             }
           },pause_time_in_milis);
    }
}
stinepike
  • 54,068
  • 14
  • 92
  • 112