I've been struggling with this problem for days. I've also checked the documentation and several topics but didn't find any solution / explanation.
I am testing my application on LG p500 but I did a few test on Droid too and I get the same result.
My application uses AlarmHandler to schedule alarm. The application works correctly on the emulator and also on the device until the device has enough free memory. When I start several other applications on the device and the memory is low the alarm will not fire anymore. As soon as I stop the "other" application the alarm works fine again.
Let me report the test and the result.
- I set an alarm on my application 10 minute later.
- I start several application (browser, google map, gmail, K9Mail,....)
- I start the catlog to see the log of my application
- Wait 15 minute without working on the phone
- After 10 minutes the alarm should be fired but nothing happen until I wakeup my phone pressing a button
- When I wake-up my phone the alarm immediatly fires and all the notificatin happen.
- I stop the "other" application I previously started (browser, google map,...)
- Set again an alarm 10 minute later
- I start the catlog to see the log of my application
- Wait without working on the phone
- 10 minutes later the alarm fires and I get notified.
I did this test several time and I get the same result.
Then I tried to set an alarm using the "Catch" application I previously downloaded from the market and I get the same behaviour so it looks like this is not a problem of my application.
Looking at the log of my application I do not see any error / exception but it looks like that when the system is low on memory something happen and the broadcast receiver does not start until the phone is waked up throught the keyboard. As soon as I wake-up the phone the receiver start and all the notification happen.
Here the code I used:
The Receiver:
public class NotificationReceiver extends BroadcastReceiver
{
public static final String LOG_TAG = "YAAS - Notification Receiver";
@Override
public void onReceive(Context context, Intent intent)
{
ScheduleActivityService.acquireStaticLock(context);
Log.i(LOG_TAG, "Received alarm - id: " + intent.getIntExtra("id", -1));
Intent intent2 = new Intent(context, ScheduleActivityService.class);
intent2.putExtra("id", intent.getIntExtra("id", -1));
context.startService(intent2);
}
}
The Service
public class ScheduleActivityService extends Service
{
public static final String LOCK_NAME_STATIC="it.hp.yaas.AppService.Static";
public static final String LOG_TAG = "YAAS - ActivityService";
private static PowerManager.WakeLock lockStatic = null;
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder
{
public ScheduleActivityService getService()
{
return ScheduleActivityService.this;
}
}
@Override
public IBinder onBind(Intent intent)
{
return mBinder;
}
public static void acquireStaticLock(Context context) {
getLock(context).acquire();
}
synchronized private static PowerManager.WakeLock getLock(Context context)
{
if (lockStatic == null)
{
PowerManager mgr = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
lockStatic = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOCK_NAME_STATIC);
lockStatic.setReferenceCounted(true);
}
return(lockStatic);
}
/**
* This method is called when an alarm fires that is its alarm time is reached.
* The system assume that the alarm fired match the alarm time of the first
* activity.
* @param intent intent fired
* @param flag
* @param startId
*/
@Override
public int onStartCommand(Intent intent, int flag, int startId)
{
super.onStartCommand(intent, flag, startId);
try {
Log.i(LOG_TAG, "Alarm fired: " + startId + " - id: " + intent.getIntExtra("id", -1));
AlarmHandler.getInstance().onAlarmFired(intent.getIntExtra("id", -1));
}
finally { getLock(this).release(); }
return START_STICKY;
}
@Override
public void onDestroy()
{
super.onDestroy();
Log.i(LOG_TAG, "Destroy");
}
}
An piece of code from AlarmHandler, the routine called to schedule the alarm:
public synchronized void onAlarmFired(int alarmId)
{
scheduledAlarmId = -1;
Alarm alarmFired = pop();
if (alarmFired == null) return;
Log.i(LOG_TAG, "onAlarmFired (Alarm: " + alarmFired + ") at (time: " + Utilities.convertDate(new Date(), "HH:mm:ss") + ")");
notifyAlarmListener(alarmFired);
if (alarmFired.reschedule(null) != null) add(alarmFired);
Alarm alarm = peek();
if (alarm != null && scheduledAlarmId != alarm.getId()) scheduleEvent(alarm);
}
/**
* Schedule an alarm through AlarmManager that trigger next activity notification
* @param alarm alarm to be scheduled
*/
private void scheduleEvent(Alarm alarm)
{
Log.i(LOG_TAG, "scheduleEvent - (Alarm: " + alarm + ")");
Intent intent = new Intent(context, NotificationReceiver.class);
intent.putExtra("id", alarm.getId());
// In reality, you would want to have a static variable for the request code instead of 192837
PendingIntent sender = PendingIntent.getBroadcast(context, 192837, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Get the AlarmManager service
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, alarm.getTime().getTime(), sender);
scheduledAlarmId = alarm.getId();
}
And finally this is a piece of Manifest file:
<activity android:name=".ListActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".EditActivity"/>
<activity android:name=".SettingsActivity"/>
<service android:name="ScheduleActivityService"
android:label="YAAS Service"/>
<receiver android:name="NotificationReceiver" />