因为在闹钟时间到达时需要发出警报(是一种Service),这需要AlarmManager来执行,警报发出后(实际上发出的是广播),作为响应者,需要一个BroadcastReceiver来接收此警报,接收后的具体行为是通过重写BroadcastReceiver之下的onReceive()来实现的。
先附上闹钟响应时(继承BroadcastReceiver)的代码,就是一个Toast:
package com.example.alarm;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast; public class AlarmReceiver extends BroadcastReceiver { @Override
public void onReceive(Context arg0, Intent arg1) {
// TODO
Toast.makeText(arg0, "时间已到", Toast.LENGTH_SHORT).show();
}}
然后是分别是‘设置闹钟’和‘取消闹钟’按钮下的逻辑操作,主要内容是用Intent去联系BroadcastReceiver;PendingIntent;用AlarmManager去设置警报时间和取消闹钟。
package com.example.alarm;
import java.util.Calendar;
import android.os.Bundle;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.TimePickerDialog;
import android.content.Intent;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TimePicker;
import android.widget.Toast;
public class MainActivity extends Activity {
Calendar calendar=Calendar.getInstance();
Button start_alarm,stop_alarm;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start_alarm=(Button) findViewById(R.id.start_alarm);
stop_alarm=(Button) findViewById(R.id.stop_alarm);
start_alarm.setOnClickListener(listener);
stop_alarm.setOnClickListener(listener);
}
View.OnClickListener listener=new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO 自动生成的方法存根
int Id=v.getId();
switch (Id){
case R.id.stop_alarm:
Intent intent=new Intent(MainActivity.this,AlarmReceiver.class);
// 此处的requestcode和flag要与设置闹钟时的PendingIntent一致。
PendingIntent pendingIntent=PendingIntent.getBroadcast(MainActivity.this, 26, intent, 0);
//获取闹钟管理器
AlarmManager alarmManager=(AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
Toast.makeText(MainActivity.this, "闹钟已取消", Toast.LENGTH_SHORT).show();
break;
case R.id.start_alarm:
calendar.setTimeInMillis(System.currentTimeMillis());
int myhour=calendar.get(Calendar.HOUR_OF_DAY);
int myminute=calendar.get(Calendar.MINUTE);
new TimePickerDialog(MainActivity.this,new TimePickerDialog.OnTimeSetListener() {
@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
// TODO 自动生成的方法存根
//设置日历的时间,主要是让日历的年月日和当前同步
calendar.setTimeInMillis(System.currentTimeMillis());
//设置日历的小时和分钟
calendar.set(Calendar.HOUR_OF_DAY, hourOfDay);//
calendar.set(Calendar.MINUTE, minute);
//将秒和毫秒设置为0
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
//建立Intent和PendingIntent来调用闹钟管理器
Intent intent=new Intent(MainActivity.this,AlarmReceiver.class);
PendingIntent pendingIntent=PendingIntent.getBroadcast(MainActivity.this, 26, intent, 0);
//获取闹钟管理器
AlarmManager alarmManager=(AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 1000*1000, pendingIntent);
Toast.makeText(MainActivity.this, "设置的闹钟时间为:"+String.valueOf(hourOfDay)+":"+String.valueOf(minute), Toast.LENGTH_SHORT).show();
}
}, myhour, myminute, true).show();//myhour, myminute是TimePickerDialog的初始显示时间
break; } } };}
这里有两点要说明:1.这里的calendar,并不是一个生活意义上的‘日历’,这里将其理解为一个可以任由我们改写时间的时间容器会比较好,而且精度高至秒。从行可看到,其时间是可以由我们自行改写的。同时,在onTimeSet()方法下,calendar的时间被赋值当前的TimePickerDialog控件的输入值。而设置闹钟最关键的就是alarmManager.set()这一步,该方法的实参是我们希望的闹钟时刻,这个时刻被存在calendar里。类似地,取消闹钟最关键的则是alarmManager.cancel(pendingIntent)这一步。这里重点要加深对calendar的理解。2.calendar.setTimeInMillis(System.currentTimeMillis());这里的‘赋时’操作,实际上是根据加法实现的,System.currentTimeMillis()是以毫秒为单位的从1970.1.1 0:0年至今的时间差,calendar.setTimeInMillis()则是重新在1970.1.1 0:0 基础上增加这段时间差,来达到今时的时间。另外,由于使用了 BroadcastReceiver 服务,因此需要在 AndroidManifest.xml中进行声明,代码如下
<receiver android:name=".AlarmReceiver" android:process=":remote"></receiver>
与<activity>并列写在<application>之内即可。
附 Intent和PendingIntent的区别:(引自链接)
a. Intent是立即使用的,而PendingIntent可以等到事件发生后触发,PendingIntent可以cancel
b. Intent在程序结束后即终止,而PendingIntent在程序结束后依然有效
c. PendingIntent自带Context,而Intent需要在某个Context内运行
d. Intent在原task中运行,PendingIntent在新的task中运行