使用AlarmReceiver和OnBootReceiver为android应用程序设置警报
我浏览了大量StackOverflow和Youtube教程来创建一个报警服务(作为我正在构建的更大应用程序的一部分使用),但它们似乎都给出了不同的、不起作用的答案,或者依赖于不推荐的不再起作用的方法 我目前使用以下代码的问题是,当我使用以下代码时:使用AlarmReceiver和OnBootReceiver为android应用程序设置警报,android,alarmmanager,Android,Alarmmanager,我浏览了大量StackOverflow和Youtube教程来创建一个报警服务(作为我正在构建的更大应用程序的一部分使用),但它们似乎都给出了不同的、不起作用的答案,或者依赖于不推荐的不再起作用的方法 我目前使用以下代码的问题是,当我使用以下代码时:alrmMgr.set(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(),pendInt)它似乎没有向报警管理器发送适当的时间(它或多或少总是发送当前时间) 但是,我知道calendar.getTim
alrmMgr.set(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(),pendInt)代码>它似乎没有向报警管理器发送适当的时间(它或多或少总是发送当前时间)
但是,我知道calendar.getTimeInMillis()会给我设置的时间(setAlarmText文本视图会正确更改)。我想知道是否有人有这方面的经验
此外,AlarmReceiver
类似乎从未被调用过,尽管我的印象是AlarmManager
会为您解决这个问题
代码如下:
public class AlarmStartPage extends Activity {
AlarmManager alrmMgr;
PendingIntent pendInt;
private TimePicker alrmTimePicker;
private static AlarmStartPage inst;
Intent myIntent;
private TextView alrmStatusView;`
protected static AlarmStartPage instance() {
return inst; // returns an instance of the current Activity
}
@Override
public void onStart() {
super.onStart(); // calls the super classes onStart, and then sets the instance to the current one
inst = this;
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_alarm_start_page); // sets the various buttons and other containers on the website
alrmTimePicker = (TimePicker) findViewById(R.id.alarmTimePicker);
ToggleButton alrmTogg = (ToggleButton) findViewById(R.id.toggleAlarmButton);
alrmMgr = (AlarmManager) getSystemService(ALARM_SERVICE);
alrmStatusView = (TextView) findViewById(R.id.alarmStatus);
setVolumeControlStream(AudioManager.STREAM_ALARM); // sets the volume to be controlled to the audiomanager so that the user can control the alarm's volume
}
public void onToggleClicked(View view) {
if (((ToggleButton) view).isChecked()) {
Log.d("MyActivity", "Alarm On!");
int hourToSet, minuteToSet; // if the toggle button is pushed, then it creates an alarm. Otherwise it cancels a previously created alarm
Calendar calendar = Calendar.getInstance();
if (Build.VERSION.SDK_INT >= 23) // the code here and the one below in the else statement are identical except for which API they cater to
{
hourToSet = alrmTimePicker.getHour();
minuteToSet = alrmTimePicker.getMinute(); // gets the TimePicker's time that the user wants if using Android Marshmallow
} else {
hourToSet = alrmTimePicker.getCurrentHour(); // gets the TimePicker's time that the user wants if using any Android Lolipop or below
minuteToSet = alrmTimePicker.getCurrentMinute();
}
// this is the code to actually do the "magic" of the REM time
int currhr = calendar.get(Calendar.HOUR_OF_DAY); // gets the current time from the system's clock
int currmin = calendar.get(Calendar.MINUTE);
boolean lessThan90 = false; // boolean to check if the current alarm is less than 90 Minutes away (1 REM cycle)
int hrDiff = 0;
int minDiff = 0;
if (hourToSet >= currhr) {
hrDiff = hourToSet - currhr; // calculating the difference between the current hour and the hour of the alarm to get the difference in the time
if (hrDiff == 0) {
if (minuteToSet > currmin) // if the alarm is for after the current time, but same hour, then it is less than 1 hour away
minDiff = minuteToSet - currmin;
else {
hrDiff = 23; // otherwise the alarm us for more than 23 hours away (same hour, but earlier time)
minDiff = 60 - (currmin - minuteToSet);
}
} else {
if (minuteToSet > currmin)
minDiff = minuteToSet - currmin;
else {
hrDiff--;
minDiff = 60 - (currmin - minuteToSet);
}
}
if (60 * hrDiff + minDiff < 90) // if prior to the 15 min shift, the alarm time is less than 90 minutes away, then it will be set as the alarm time
lessThan90 = true;
}
currmin += 15; // add 15 min to the current time, and below, change the hour and minute accordingly
if (currmin >= 60) {
currmin = currmin % 60;
currhr++;
if (currhr >= 24)
currhr = currhr % 24;
}
if (!lessThan90) // only if the alarm time is more than 90 minutes away, it will try to do this (which it will try to do
{ // by defualt since lessThan90 is initalized to false (or it is set to true by the above if else statement
if (hourToSet >= currhr) {
hrDiff = hourToSet - currhr;
if (hrDiff == 0) // same logic as earlier, checks if the same hour as the alarm, then checks if the alarm is before or after the current time
{
if (minuteToSet > currmin) // if the alarm is set for a later time (which means that it is less than 90 minutes away)
minDiff = minuteToSet - currmin;
else // otherwise the alarm is set for 23 hours and some minutes away
{
minDiff = 60 - (currmin - minuteToSet);
hrDiff = 23;
}
} else {
if (minuteToSet > currmin)
minDiff = minuteToSet - currmin;
else {
hrDiff--;
minDiff = 60 - (currmin - minuteToSet);
}
}
} else if (hourToSet < currhr) // if the alarm time is before the current time (then it must loop over midnight and restart from 0 again)
hrDiff = 24 - (currhr - hourToSet);
}
int totalMinutesInBetween = 60 * hrDiff + minDiff;
if (totalMinutesInBetween < 90) // if the total minutes between the alarm and the current time (after the 15 min shift) is less than 90 minutes
lessThan90 = true; // it is less than 1 REM shift away
if (!lessThan90) // If there are more than 90 minutes of difference, then a REM cycle is ACTUALLY possible
{
int possibleRem = totalMinutesInBetween / 90; // the possible amount of REM cycles between now and the alarm time
for (int i = 0; i < possibleRem; i++) {
currhr++; // the time is altered by 90 minute cycles (looping around after 60 minutes or after 24 hours) to get the appropiate REM time
if (currhr >= 24)
currhr = currhr % 24;
currmin += 30;
if (currmin >= 60) {
currmin = currmin % 60; // looping the minutes over 60
currhr++;
if (currhr >= 24)
currhr = currhr % 24; // looping the hours after 24 hours
}
}
hourToSet = currhr;
minuteToSet = currmin;
}
calendar.set(Calendar.HOUR_OF_DAY, hourToSet); // the calendar sets the final REM time
calendar.set(Calendar.MINUTE, minuteToSet);
myIntent = new Intent(AlarmStartPage.this, AlarmReceiver.class);
pendInt = PendingIntent.getBroadcast(AlarmStartPage.this, 0, myIntent, 0); // new intent as well as a pending intent to notify the system of the alarm (uses Alarm Receiver and Alarm Service)
alrmMgr.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendInt); // alarmmanager is used to set the alarm
if (minuteToSet > 9)
setAlarmText("An alarm has been placed for " + hourToSet + ":" + minuteToSet + " (in military time). If you shut down" +
" this app, please do not open it again until the alarm that you set is over (otherwise the alarm will reset itself)."); // alarm text is changed to notify the user
else
setAlarmText("An alarm has been placed for " + hourToSet + ":0" + minuteToSet + " (in military time). If you shut down" +
" this app, please do not open it again until the alarm that you set is over (otherwise the alarm will reset itself).");
} else {
alrmMgr.cancel(pendInt); //cancels the current Intent (effectively stopping the alarm)
stopService(myIntent);
setAlarmText("The previous alarm was canceled."); // changes the text on the textbox under the time picker
Log.d("MyActivity", "Alarm OFF");
}
}
public void setAlarmText(String textToShow) {
alrmStatusView.setText(textToShow); // sets the text for the textbox below the TimePicker
}
@Override
public void onDestroy() {
super.onDestroy(); // calls the super classes destroy method to destroy the activity
}
}
AlarmService.java:
public class AlarmService extends IntentService {
private NotificationManager alarmNotificationManager;`
public AlarmService() {
super("AlarmService");
}
@Override
public void onHandleIntent(Intent intent) {
sendNotification("Wake Up! Your alarm has been rung!!!!"); // sends the notification to the phone that the alarm is ringing
}
private void sendNotification(String msg) {
Log.d("AlarmService", "Preparing to send notification...: " + msg);
alarmNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, AlarmStartPage.class), 0); // creates the notification and sets the icon for the notification
NotificationCompat.Builder alarmNotificationBuilder = new NotificationCompat.Builder(
this).setContentTitle("Alarm").setSmallIcon(R.mipmap.ic_launcher).setStyle(new NotificationCompat.BigTextStyle().bigText(msg)).setContentText(msg);
alarmNotificationBuilder.setContentIntent(contentIntent);
alarmNotificationManager.notify(1, alarmNotificationBuilder.build());
Log.d("AlarmService", "Notification sent.");
}
}
OnBootReceiver:
public class OnBootReceiver extends BroadcastReceiver {
private static final int WAITING_PERIOD = 10000; // 10 seconds (aka 10000 milliseconds)`
@Override
public void onReceive(Context context, Intent intent)
{
AlarmManager aMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); // allows previously created alarms to still exist on bootup.
Intent i = new Intent(context, AlarmReceiver.class);
PendingIntent pI = PendingIntent.getBroadcast(context, 0, i, 0);
aMgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), WAITING_PERIOD, pI);
}
}
代码也可以在上找到
任何帮助都将不胜感激
编辑:
这是我们提出的解决方案,以防对任何人有所帮助:
尼克:所以广播确实启动了运行通知的服务,但问题是声音应该在哪里改变,而不是在哪里
尼克:好的,那么有什么原因让你从接收器播放声音,而不是直接从通知对象播放声音?我想那会管用的
我:嗯,我在听几个不同的教程,它们似乎都在听筒里
尼克:在service sendNotification方法中,尝试更改为:
private void sendNotification(String msg) {
Log.d("AlarmService", "Preparing to send notification...: " + msg);
alarmNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, AlarmStartPage.class), 0); // creates the notification and sets the icon for the notification
Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
NotificationCompat.Builder alarmNotificationBuilder = new NotificationCompat.Builder(
this)
.setContentTitle("Alarm")
.setSmallIcon(R.mipmap.ic_launcher)
.setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
.setContentText(msg)
.setSound(soundUri);
alarmNotificationBuilder.setContentIntent(contentIntent);
alarmNotificationManager.notify(1, alarmNotificationBuilder.build());
Log.d("AlarmService", "Notification sent.");
}
尼克:很确定这是正确的通知方式。。使用铃声的旧方法可能已被弃用。现在请评论铃声部分
尼克:从AlarmManager运行服务的正确方法是让它启动一个广播接收器,然后启动你的IntentService
尼克:我完全忘了为什么会这样。。但你肯定想这样做。我曾考虑过在接收器中运行所有程序,但最好是这样做,alarm->receiver->IntentService,其中包含所有代码要在正确的时间触发警报,请在AlarmStartPage
活动中实例化日历对象后添加此行:
calendar.setTimeInMillis(System.currentTimeMillis());
因此,当您创建日历时,您的代码应该如下所示:
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
这将确保其他日历参数设置正确,因为在设置之前,日历参数仅设置小时/分钟,而其余参数未完全配置。这可能不是问题所在,但请先尝试一下,看看是否有任何变化。添加calendar.setTimeInMillis(System.currentTimeMillis())代码>就在这一行之后:Calendar Calendar=Calendar.getInstance()在AlarmStartPage
活动中的code>。添加该行有助于不再在当前时间创建报警,而是在时间选择器设置的时间创建报警。非常感谢。然而,出于某种原因,即使我在AlarmReceiver.java中设置了断点,程序也不会进入其中(即使警报最终响起并发出祝酒声)。酷!我为问题的那一部分添加了一个回复帖子。我不完全理解你关于AlarmReceiver的意思,你到底想实现什么?我希望能弄明白。让我澄清一下。警报响起后,会向用户敬酒,告诉用户警报正在响。这是在AlarmService类中完成的。但是,运行的报警依赖于默认的通知噪声,而不是默认的报警噪声(这是我在AlarmReceiver.java中尝试更改的)。然而OnReceive方法似乎从未被调用。所有日志语句都不会被打印出来。好的。但是,我没有看到在您的代码中任何地方制作吐司
?
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());