Jake Duncan Jake Duncan - 1 month ago 16
Android Question

Sleep VS alarmManager.set VS alarmManager.setRepeat VS Handler

I'm looking for the most efficient way to perform a simple task. As a new android developer, I'm not too sure which of these strategies would be best for my app in terms of memory efficiency. I imagine some of these approaches might cause threading issues that I'm unaware of.

All three solutions are currently behaving as desired.

It's a really simple app. The idea is that my MainActivity starts an IntentService which will be running in the background after the app is opened. All the functionality I need right now is for a notification to be created at random intervals throughout the day(about an hour apart), indefinitely, until stopped by the user. The notification is made in a simple void method, displaying notification as text and vibrating the phone once.

My MainActivity starts the IntentService:

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Intent intent = new Intent(this, NotificationService.class);
startService(intent);
}
}


My IntentService is very simple. It is called NotificationService, extends IntentService, and only overrides the onHandleIntent method. The constructor is empty except for super("Service"). The question comes in how to cause the notifications to pop up throughout the day in the background in the most efficient way. This in my implementation is done in the onHandleIntent method for all three methods.

Method One:

@Override
protected void onHandleIntent(Intent intent) {

makeNotification();

AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

PendingIntent pintent = PendingIntent.getService(
getApplicationContext(), 0, intent, 0);

alarm.cancel(pintent);

alarm.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()
+ 60000 * 60, pintent);
}


Note that with this, the user would have to uninstall the app to get the notifications to stop, which is not desirable (although I think I could just add a button or something that would cancel the intent)

Method Two:

protected void onHandleIntent(Intent intent) {

makeNotification();

AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);

PendingIntent pintent = PendingIntent.getService(
getApplicationContext(), 0, intent, 0);

alarm.cancel(pintent);

alarm.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()
+ 60*1000, 60000*60 ,pintent);
}


Method three:

@Override
protected void onHandleIntent(Intent intent) {

makeNotification();

try {
sleep(60000 * 60);
startService(intent);
} catch (InterruptedException e) {
e.printStackTrace();
}
}


Can someone please help me with deciding the pros/cons of these three methods? Im not sure I understand which one would be ideal, although they all three give me proper functionality. As a side note, in my research I've noticed a "Handler" class which may also be useful here.

Answer

All the functionality I need right now is for a notification to be created at random intervals throughout the day(about an hour apart), indefinitely, until stopped by the user.

The AlarmManager, and potentially JobScheduler, are the only viable options.

The idea is that my MainActivity starts an IntentService which will be running in the background after the app is opened

Not really. An IntentService will only be running for as long as it takes to complete onHandleIntent() (including executing it N times if N commands are sent to it in rapid succession). An IntentService can run for a little while, but it is designed to handle some sort of business logic transaction. It is not designed to run indefinitely, and doing so would be bad for the user anyway.

Can someone please help me with deciding the pros/cons of these three methods?

Option three is unusable. First, it will not be reliable, as it stops working once your process is terminated. Second, it ties up a hunk of system RAM for no good reason, RAM that the user could put to more productive use. Only have a service running when it is actively delivering value to the user. Watching the clock tick is not actively delivering value to the user.

I've noticed a "Handler" class which may also be useful here

No, as it will suffer from the same problems as option three.

With regards to your two AlarmManager options, it boils down to whether you want regularly-occurring alarms (setRepeating()) or irregularly-occurring alarms (set()).

If you go the setRepeating() option, move the AlarmManager code out of the service and into the activity. There is no point — and definite costs — to calling setRepeating() on every alarm. After all, the point behind setRepeating() is that it knows to repeat, so you do not need to tell it on every occurrence "oh, hey, I know that I told you the last 1,337 times that you should repeat, but, um, don't forget to repeat, m'kay?".

With the set() option, since you are specifically not asking for the alarms to repeat, you would continue to schedule them in the service (or perhaps once from the activity, then the rest from the service), more or less as you have it.