What is the best way to setup an appointment reminder on Android? I am hoping there is something better than AlarmManager.
Lets say you have an app that allows the user to store a reminder for their next dental appointment (or any appointment - it doesn't matter - but assume there is only 1 or 2 appointments per year). As that appointment approaches it should pop-up a notification, and it will work even if the app isn't running (assuming the phone is switched on).
The AlarmManager could do it, but it would have to be reactivated every time the device reboots. This is ugly for 3 reasons:-
It do开发者_开发技巧esn't work if the app is installed to the SD card (and many users will flame apps that don't provide app2sd support).
If there isn't a reminder stored the service must still run at boot-up to discover that. To my knowledge it's impossible to programmatically setup a BOOT_COMPLETED listener for only when it's needed.
Nobody wants their phone to be bogged down with these types of services at boot-up.
So I was wondering if anyone knew of a better solution? I just want to store a long-term appointment. Preferably using internal Android services without relying on access to Google calender etc, or anything like that. Any ideas?
The correct solution is the AlarmManager. You can programmatically change whether you are launched at boot by using PackageManager.setComponentEnabledSetting() to enable your receiver component only when you have an alarm scheduled.
In practice there is no use in the AlarmManager retaining alarms across boots, because the vast majority of apps need to re-evaluate the alarms after a boot. For example, a calendar needs to resync them etc. And retaining them has a big downside: bugs in applications can leave junk data in the alarm manager that even a reboot won't clear out.
As for the SD card, you can watch for http://developer.android.com/reference/android/content/Intent.html#ACTION_EXTERNAL_APPLICATIONS_AVAILABLE to find out when the external storage is re-mounted and your app can run again.
Unfortunately there really isn't an alternative to the BOOT_COMPLETED intent, and the SD issue probably won't change. If you want this functionality you will just need to live with ignorant users flaming you. If you do a decent job the boot receiver won't significantly slow the device down.
One alternative would be an SMS listener and you send an SMS with triggering info at the required time: no boot receiver necessary, no activity if they don't hav a appointment. Somewhat more intrusive as far as the SMS broadcast receiver goes, but you're not exactly blessed with choices. You could also use C2DM in a similar fashion, but either of those options (SMS or C2DM) require significantly more server side infrastructure (i.e. moe than none).
As far as the SD issue is concerned, the actual solution is for device manufacturers to do what the iphone does, and put a comparatively massive amount of flash that can't be removed on each device: the SD craziness is quite frankly utterly unnecessary. I can buy a 4gb sd flash for $4 retail: if that is too expensive for the device vendors/carriers to provide a superior user experience then they deserve to go out of business.
If there isn't a reminder stored the service must still run at boot-up to discover that. To my knowledge it's impossible to programmatically setup a BOOT_COMPLETED listener for only when it's needed.
Sure there is. Simply disable the component using PackageManager
, enabling it when needed. For example, here is an OnSharedPreferenceChangeListener
that enables/disables a boot-time receiver based upon whether the user checks an "alarm" CheckBoxPreference
:
SharedPreferences.OnSharedPreferenceChangeListener onChange=
new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if ("alarm".equals(key)) {
boolean enabled=prefs.getBoolean(key, false);
int flag=(enabled ?
PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
ComponentName component=new ComponentName(EditPreferences.this,
OnBootReceiver.class);
getPackageManager()
.setComponentEnabledSetting(component, flag,
PackageManager.DONT_KILL_APP);
if (enabled) {
OnBootReceiver.setAlarm(EditPreferences.this);
}
else {
OnBootReceiver.cancelAlarm(EditPreferences.this);
}
}
else if ("alarm_time".equals(key)) {
OnBootReceiver.cancelAlarm(EditPreferences.this);
OnBootReceiver.setAlarm(EditPreferences.this);
}
}
};
Nobody wants their phone to be bogged down with these types of services at boot-up.
A recent test indicated that there are dozens of BOOT_COMPLETED
listeners on a conventional Android device, including a bunch from the OS. I agree that it's good form to disable the component if it is not needed, since that's not too tough to implement. However, I wouldn't worry about it when it is truly needed.
精彩评论