因爲在鬧鐘時間到達時需要發出警報(是一種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中運行