13
votes

So I've got a BroadcastReceiver and the AlarmManager.

Let's say I create the Pending Intents like so:

Intent i;
i = new Intent(context, MyReceiver.class);
i.setAction(MyReceiver.ACTION_1);
i.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
pendingIntent1 = PendingIntent.getBroadcast(context, 1, i, PendingIntent.FLAG_UPDATE_CURRENT);

i = new Intent(context, MyReceiver.class);
i.setAction(MyReceiver.ACTION_2);
i.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
pendingIntent2 = PendingIntent.getBroadcast(context, 2, i, PendingIntent.FLAG_UPDATE_CURRENT);

And schedule the alarms like so:

now = SystemClock.elapsedRealtime();
long time1 = now + 10 * 1000;
long time2 = time1 + 60 * 1000;

am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, time1, pendingIntent1);
am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, time2, pendingIntent2);

I am now experiencing that my broadcast receiver gets the broadcast for ACTION_1 quite reliably, while ACTION_2 is often not being delivered. So onReceive is rarely or never executed with an intent holding the action ACTION_2. How comes that? I thought, *_WAKEUP makes sure that broadcasts are being delivered anyway?

[Update 09/15/2015] - For testing purposes I'm trying to print out a Log message in my onReceive method. Still not working. - I've tried using setExact on AlarmManager now. Still not working. - I've even tried using WakefulBroadcastReceiver. Still not working. - I've found out, however, that the device reliably wakes up when in battery charged state. What could cause this problem? I've read everywhere that broadcast receivers are guaranteed to be executed if triggered by the alarm manager via a pending intent (and not doing too much stuff in onReceive). Do I maybe have some aggressive energy saving policy on my phone which I can't really work against (without acquiring a long wake lock, see comments)?

[Update 09/19/2015] I have just tested some alarm clock app (https://play.google.com/store/apps/details?id=com.alarmclock.xtreme.free) on Google Play and it does not reliably wake up the phone, too. I guess, it's really a bug and not my fault. I'll stick to the wake lock solution then, I guess.

4
what's the value of showAt?Sam Dozor
Oups sorry, fixed. It was meant to be time1. The app is basically about showing a dialog (in a transparent activity) after some time the screen went off (here 10 secs) and hiding it again, if the screen was off for too long (here 10+60=70 secs).flxapps
I've now solved my problem by acquiring a wake lock like so: wakeLock.acquire(time2 - now + 5000); (keeping the phone awake for - in the upper example - 70 secs plus 5 secs as a buffer) - However, I feel like this is a rather hacky solution. What do you think? Is it legitimate or too dirty, probably causing problems?flxapps
Which phone are you testing on? Sony models have an aggressive power saving mode enabled by default which can stop services from waking up.pmont
Yeup, it's a Sony Xperia Z1 Compact... I guess, the method with manually acquiring a wake lock with timeout is - as dirty as it is - the most reliable solution then?flxapps

4 Answers

6
votes

I encountered the same problem, the solution i found is to create the intent only by action string, and register that receiver action in manifest. try changing the intent to something like this:

i = new Intent("com.app.ACTION_ONE");

then in your manifest file add to your receiver the following:

<intent-filter>
    <action android:name="com.app.ACTION_ONE" />
</intent-filter>

My guess is if you dont register at least 1 action to the recevier he just dies when the application procces is terminated.

Hope it works, good luck.

2
votes

Did you registered the BroadcastReceiver (or from the Manifest)?

 registerReceiver(new MyReceiver(), new IntentFilter(MyReceiver.class.getName()));

I used last time almost the same methods, but with AlarmManager.RTC_WAKEUP - if you don't want to wake the device from deep sleep, use AlarmManager.RTC

long time = System.currentTimeMillis() + 10*1000;
alarmMgr.set(AlarmManager.RTC_WAKEUP, time, alarmIntent);

The alarmIntent like:

alarmIntent = PendingIntent.getBroadcast(this, 0, new Intent(MyReceiver.class.getName()), PendingIntent.FLAG_CANCEL_CURRENT);
1
votes

There is few things it might be usefull to note:

  1. You are using AlarmManager.set() method witch doesnt not guarantee time of the delivery, if you want to have alarm to be triggered at exact time use AlarmManager.setExact()

  2. You broadcast intent doesn't make sense for me. It is implicit, but broadcasts are not supposed to be. Such intent could be reson for strange android behavior. If you want to have implicit intent send it directly to service handling it. In receiver case I would recommend to use:

    Intent intent = new Intent(Contants.Action1);
    
  3. If your receiver is defined in manifest intents will be delivered even if all activities of your application are dead, if receiver registered dynamicly it can receive intents only while thread on whitch it was crated is alive.

  4. Different versions of Android trying to optimise alarms in slightly different way, but the goal is to trigger as many alarms as posible at the same time to achive better battery performance.

All this can be quite confusing. But intents are guaranteed to be delivered, if receiver is registered correctly.

0
votes

Take a look at the settings for "Stamina Mode" on your sony devices. Try disabling Stamina mode or add your app to the whitelist of apps allowed when stamina mode is on.

Hope this helps.