1、新建一个activity,命名为AlarmActivity,如下:
public class AlarmActivity extends AppCompatActivity {
private TextView tv_alarm;
private int mDelay;
private int[] delayArr = {5, 10, 15, 20, 25, 30};
private String[] delayDescArr = {"5秒", "10秒", "15秒", "20秒", "25秒", "30秒"};
private String ALARM_EVENT = "com.example.senior.activity.broad.AlarmActivity.AlarmReceiver";
private static String mDesc = ""; // 闹钟时间到达的描述
private static boolean isArrived = false; // 闹钟时间是否到达
private AlarmReceiver alarmReceiver; // 闹钟的广播接收器
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_alarm);
tv_alarm = findViewById(R.id.tv_alarm);
initButton();
initDelaySpinner();
}
@Override
protected void onStart() {
super.onStart();
// 从Android9.0开始,系统不在支持静态广播,应用广播只能通过动态注册
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
alarmReceiver = new AlarmReceiver(); // 创建一个闹钟的广播接收器
IntentFilter filter = new IntentFilter(ALARM_EVENT);
registerReceiver(alarmReceiver, filter); // 注册广播接收器,注册之后才能正常接收广播
}
}
@Override
protected void onStop() {
super.onStop();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
unregisterReceiver(alarmReceiver);
}
}
private void initButton() {
findViewById(R.id.btn_alarm).setOnClickListener(v -> {
// 创建一个广播事件的意图
Intent intent = new Intent(ALARM_EVENT);
// 创建一个用于广播的延时意图
PendingIntent pIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);;
// 从系统服务中获取闹钟管理器
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, mDelay); // 给当前时间加上若干秒
// 开始设定闹钟,延时若干秒后,携带延时意图发送闹钟广播
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pIntent);
mDesc = DateUtil.getNowTime() + " 设置闹钟";
tv_alarm.setText(mDesc);
});
}
private void initDelaySpinner() {
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.item_select, delayDescArr);
Spinner sp_delay = findViewById(R.id.sp_delay);
sp_delay.setPrompt("请选择闹钟延时");
sp_delay.setAdapter(adapter);
sp_delay.setSelection(0);
sp_delay.setOnItemSelectedListener(new DelaySelectedListener());
}
private class DelaySelectedListener implements AdapterView.OnItemSelectedListener {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
mDelay = delayArr[position];
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
}
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null) {
return;
}
// if (tv_alarm != null && !isArrived) {
// isArrived = true;
mDesc = String.format("%s\n%s 闹钟时间到达", mDesc, DateUtil.getNowTime());
tv_alarm.setText(mDesc);
// }
}
}
}
2、AlarmActivity对应的布局文件为activity_alarm,如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="5dp"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="40dp">
<TextView
android:id="@+id/tv_delay"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="闹钟延时"
android:textColor="@color/black"
android:textSize="17sp" />
<Spinner
android:id="@+id/sp_delay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:spinnerMode="dialog"
android:layout_toRightOf="@id/tv_delay" />
</RelativeLayout>
<Button
android:id="@+id/btn_alarm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="设置闹钟"
android:textSize="20sp" />
<TextView
android:id="@+id/tv_alarm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="这里是闹钟的消息"
android:textColor="@color/contentGray"
android:textSize="15sp" />
</LinearLayout>
3、日期帮助类为DateUtil,如下:
public class DateUtil {
public static String getNowDateTime(String formatStr) {
if (TextUtils.isEmpty(formatStr)) {
formatStr = "yyyyMMddHHmmss";
}
SimpleDateFormat sdf = new SimpleDateFormat(formatStr);
return sdf.format(new Date());
}
public static String getNowDateTime() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(new Date());
}
public static String getNowTime() {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
return sdf.format(new Date());
}
public static String getNowTimeDetail() {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
return sdf.format(new Date());
}
public static String formatDate(long time) {
Date date = new Date(time);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
return sdf.format(date);
}
}
4、Android9.0之前的静态广播如下,再AndroidManifest.xml中设置,如下:
注意:要在
<receiver android:name=".activity.broad.AlarmActivity$AlarmReceiver"
android:exported="true">
<intent-filter>
<action
android:name="com.example.senior.activity.broad.AlarmActivity.AlarmReceiver" />
</intent-filter>
</receiver>
5、效果图如下:

6、说明
- PendingIntent 是延迟的意图,只要不是立即传递的消息,都用PendingIntent
- 而平常开发通过activity和broadcast传递消息都要求立即处理,这里用Intent
- PendingIntent 调用了getBroadcast 方法,表示这次携带的消息用于发送广播
- AlarmManager 的set 方法用于设置一次性定时器
- 该方法的第一个参数表示定时器类型,AlarmManager.RTC_WAKEUP 指:定时器即使在睡眠状态下也会启用
- 第二个参数表示任务的执行时间
- 第三个参数表示携带消息的延时任务