Reputation: 663
I need to have a piece of code run every time period, even if the app is killed or the device sleeps.
I am using AlarmManager
to achieve this and it kinda works, but when the device sleeps for about five minutes the Service
is not being called anymore... Does anyone know what am i doing wrong ??
here is my code:
public class Profiler extends IntentService {
public static final int ALARM_MANAGER_ID = 21436587;
public Profiler() {
super("Profiler");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
JodaTimeAndroid.init(getApplicationContext());
System.out.println("Testing profiles");
List<Profile> profiles = MainActivity.getStoredProfiles(getApplicationContext());
if (profiles != null) {
for (Profile profile : profiles) {
if(profile.check()) {
profile.set(getApplicationContext());
}
}
}
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent intent2 = new Intent(getApplicationContext(), Profiler.class);
PendingIntent pIntent = PendingIntent.getService(getApplicationContext(), ALARM_MANAGER_ID, intent2, PendingIntent.FLAG_CANCEL_CURRENT);
alarmManager.setExact(AlarmManager.RTC_WAKEUP, DateTime.now().plusSeconds(10).getMillis(), pIntent);
}
}
And one more question. Is this method of calling service reliable ??
Here is the log
07-24 11:31:24.654 17689-19078/cz.fjerabek.soundprofiler I/System.out: {"type":"Time","hour":0,"minute":0}
07-24 11:31:34.671 17689-20364/cz.fjerabek.soundprofiler I/System.out: Testing profiles
07-24 11:31:34.673 17689-20364/cz.fjerabek.soundprofiler I/System.out: {"type":"Time","hour":11,"minute":15}
07-24 11:31:34.674 17689-20364/cz.fjerabek.soundprofiler I/System.out: {"type":"Time","hour":0,"minute":0}
07-24 11:31:44.692 17689-21571/cz.fjerabek.soundprofiler I/System.out: Testing profiles
07-24 11:31:44.693 17689-21571/cz.fjerabek.soundprofiler I/System.out: {"type":"Time","hour":11,"minute":15}
07-24 11:31:44.694 17689-21571/cz.fjerabek.soundprofiler I/System.out: {"type":"Time","hour":0,"minute":0}
07-24 11:31:54.704 17689-22753/cz.fjerabek.soundprofiler I/System.out: Testing profiles
07-24 11:31:54.705 17689-22753/cz.fjerabek.soundprofiler I/System.out: {"type":"Time","hour":11,"minute":15}
07-24 11:31:54.706 17689-22753/cz.fjerabek.soundprofiler I/System.out: {"type":"Time","hour":0,"minute":0}
07-24 11:32:04.717 17689-24015/cz.fjerabek.soundprofiler I/System.out: Testing profiles
07-24 11:32:04.718 17689-24015/cz.fjerabek.soundprofiler I/System.out: {"type":"Time","hour":11,"minute":15}
07-24 11:32:04.718 17689-24015/cz.fjerabek.soundprofiler I/System.out: {"type":"Time","hour":0,"minute":0}
07-24 11:35:29.032 17689-17475/cz.fjerabek.soundprofiler I/System.out: Testing profiles
07-24 11:35:29.040 17689-17475/cz.fjerabek.soundprofiler I/System.out: {"type":"Time","hour":11,"minute":15}
07-24 11:35:29.050 17689-17475/cz.fjerabek.soundprofiler I/System.out: {"type":"Time","hour":0,"minute":0}
[ 07-24 11:35:29.056 17476:17476 I/ ]
power log dlsym ok
the application was started at 11:31, and now its 11:40 as you can see the last execution of the code was at 11:35 and before that at 11:32 its 3 minutes then it seems like its getting called every 5 minutes.
I am starting the service with:
Intent bgServiceIntent = new Intent(getApplicationContext(), Profiler.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
if(checkNotificationPolicy(getApplicationContext())) {
startService(bgServiceIntent);
}
} else {
startService(bgServiceIntent);
}
Device i am using: HUAWEI P9 lite (VNS-L21)
Upvotes: 4
Views: 772
Reputation: 19417
The cause of the problem is most probably Doze.
From its docs regarding AlarmManager
:
To help with scheduling alarms, Android 6.0 (API level 23) introduces two new
AlarmManager
methods:setAndAllowWhileIdle()
andsetExactAndAllowWhileIdle()
. With these methods, you can set alarms that will fire even if the device is in Doze.
You should call the appropriate AlarmManager
method based on the API level to make sure the alarm goes off even when the device is asleep:
if (Build.VERSION.SDK_INT >= 23) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,
alarmMillis, alarmIntent);
} else if (Build.VERSION.SDK_INT >= 19) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP,
alarmMillis, alarmIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP,
alarmMillis, alarmIntent);
}
Take the following into account:
Neither
setAndAllowWhileIdle()
norsetExactAndAllowWhileIdle()
can fire alarms more than once per 9 minutes, per app.
As you said you're testing on a Huawei device.
Huawei (among other manufacturers) has implemented certain battery saver functions that can prevent alarms from going off. You have to add your app to the "protected" apps.
Check out the following questions: 1 & 2
It is not recommended to do this programmatically, a proper solution could be to warn your users at startup (with an AlertDialog
for example) to manually make your app "protected" in the battery manager.
Upvotes: 5