花了一周時間突發(fā)奇想寫了一個個性鬧鐘應用,名叫"搖搖醒"。顧名思義,當預設的鬧鐘時間到時,鬧鐘響起,并且等待用戶搖晃手機。直到一定的閾值之后才能停下,經(jīng)過不斷的測試調整,基本上用戶在關閉鬧鐘的時候能夠保證清醒狀態(tài)??梢詾閺V大的起床困難戶解決實際問題~當然應用中也有許多不足之處,我也會繼續(xù)修改,同時及時在GITHUB上更新源代碼也希望大家一起幫助整改。下面介紹一下整個應用的設計思路。
應用中需要解決的主要問題:
- AlarmManager的使用。這是使用android鬧鐘的必須類,可以設置鬧鐘重復提醒,切換關閉與打開狀態(tài)。以及跳轉的廣播。
- Broadcast的使用。通過廣播的方式打開acivity,實現(xiàn)搖晃鬧鐘。
- 使用播放鈴聲、控制振動器。通過MediaPlayer和Vibrator類來使鬧鐘自由切換振動和鈴聲兩種方式來提醒用戶。
- SensorManager的使用。程序中需要用SensorManager來打開加速度傳感器捕捉用戶搖晃手機的力度,從而判斷用戶清醒值。
- 鎖屏彈窗。鬧鐘時間到的時候,需要在用戶手機鎖屏的時候開啟提醒。
- 定時器。通過精準定時器來計算從鬧鐘到點到搖晃接觸鬧鐘的時間。
一、鬧鐘部分
首先要做的是完成的是應用的鬧鐘部分。在此之前首先要介紹一下Android全局定時器——AlarmManager類。
AlarmManager的作用文檔中的解釋是:在特定的時刻為我們廣播一個指定的Intent。簡單的說就是我們設定一個時間,然后在該時間到來時,AlarmManager為我們廣播一個我們設定的Intent, 從而進入到我們制定的程序完成相應的動作。創(chuàng)建AlarmManager對象需要通過如下代碼:
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
AlarmManager類提供的兩個非常重要的方法:
? void set(int type, long triggerAtTime, PendingIntent operation) //設置一個鬧鐘
? void setRepeating(int type, long triggerAtTime, long interval, PendingIntent operate // 設置一個會重復的鬧鐘
type :
? ELAPSED_REALTIME
在指定的延時過后,發(fā)送廣播,但不喚醒設備。
? ELAPSED_REALTIME_WAKEUP
在指定的演示后,發(fā)送廣播,并喚醒設備
延時是要把系統(tǒng)啟動的時間SystemClock.elapsedRealtime()算進去的,具體用法看代碼。
? RTC
在指定的時刻,發(fā)送廣播,但不喚醒設備
? RTC_WAKEUP
在指定的時刻,發(fā)送廣播,并喚醒設備
triggerAtTime :首次觸發(fā)時間
** operation :**PenddingIntent對象
interval :重復觸發(fā)間隔時間
主界面非常簡單,每個鬧鐘對象設置兩個按鈕。一個設置時間,一個用于開關。
如圖:

在菜單項中可以選擇添加或者刪除鬧鐘。如圖:

其中布局文件代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp" >
<ToggleButton
android:id="@+id/btn_enClk"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_margin="10dp"
android:layout_marginRight="10dp"
android:checked="false"
android:background="@drawable/small_button" />
<Button
android:id="@+id/btn_setClock"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/btn_enClk"
android:layout_toLeftOf="@+id/btn_enClk"
android:background="@drawable/button"
android:text="設置鬧鐘" />
</RelativeLayout>
</LinearLayout>
按下鬧鐘按鈕會彈出對話框,要求用戶輸入時間,鬧鐘方式。如下圖:

鬧鐘時間旁邊是一個ToggleButton,用于設置鬧鐘開關。這兩個按鍵公用一個觸發(fā)事件。按鍵觸發(fā)事件代碼如下:
@Override
public void onClick(View v)
{
switch (v.getId())
{
case R.id.btn_setClock:
setAlarmLayout = (LinearLayout) inflater.inflate(
R.layout.alarm_dialog, null);
togbtn_AlarmStyle = (ToggleButton) setAlarmLayout
.findViewById(R.id.togbtn_alarm_style);
togbtn_AlarmStyle.setChecked(sharedData.getBoolean("style",
false));
timePicker = (TimePicker) setAlarmLayout
.findViewById(R.id.timepicker);
timePicker.setIs24HourView(true);
new AlertDialog.Builder(MainActivity.this)
.setView(setAlarmLayout)
.setTitle("設置鬧鐘時間")
.setPositiveButton("確定",
new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog,
int which)
{
disableClk();
enableClk();
if (togbtn_AlarmStyle.isChecked())
{
MainActivity.setAlarmStyle(true);
}
else
{
MainActivity.setAlarmStyle(false);
}
edit.putBoolean("style",
togbtn_AlarmStyle.isChecked());
btn_enClk.setChecked(true);
Toast.makeText(MainActivity.this,
"鬧鐘設置成功", Toast.LENGTH_LONG)
.show();// 提示用戶
}
}).setNegativeButton("取消", null).show();
break;
case R.id.btn_enClk:
if (btn_enClk.isChecked())
{
enableClk(); //打開鬧鐘
}
else
{
disableClk(); //關閉鬧鐘
}
break;
}
}
}
其中要注意兩點。一個就是TimePicker的使用,可以用24小時計時法或者12小時計時法,但是在設置AlarmManager的時候默認是用24小時,所以要注意這個關系,這里我都是用的24小時計時法。另外打開和關閉鬧鐘的函數(shù):enableClk()和disableClk()這兩個函數(shù)。disableClk()當中里面只有一句話,通過alarmManager.cancel(pi); 函數(shù)關閉鬧鐘。主要是要注意enableClk()函數(shù),首先看看代碼:
private void enableClk()
{
timePicker = (TimePicker) setAlarmLayout
.findViewById(R.id.timepicker);
c.set(Calendar.HOUR_OF_DAY, timePicker.getCurrentHour()); // 設置鬧鐘小時數(shù)
c.set(Calendar.MINUTE, timePicker.getCurrentMinute()); // 設置鬧鐘的分鐘數(shù)
c.set(Calendar.SECOND, 0); // 設置鬧鐘的秒數(shù)
c.set(Calendar.MILLISECOND, 0); // 設置鬧鐘的毫秒數(shù)
if (c.getTimeInMillis() - System.currentTimeMillis() < 0)
{
c.roll(Calendar.DATE, 1);
}
btn.setText(sdf.format(new Date(c.getTimeInMillis())));
intent = new Intent(MainActivity.this, AlarmReceiver.class); // 創(chuàng)建Intent對象
pi = PendingIntent.getBroadcast(MainActivity.this, 0, intent, 0); // 創(chuàng)建PendingIntent
alarmManager.setRepeating(AlarmManager.RTC, // 設置鬧鐘,當前時間就喚醒
c.getTimeInMillis(), 24 * 60 * 60 * 1000, pi);
}
AlarmManager有個特性,就是如果你設置的時間是已經(jīng)過去的時間,那么會立即發(fā)出廣播。這樣明顯是和我們所希望的鬧鐘功能不相符合的,所以在這里我做了一個判斷,如果時間已經(jīng)過去,我會通過roll函數(shù)將時間延后一天。接下來傳入廣播接收器的類創(chuàng)建intent對象,用PendingIntent(可以脫離acivity而存在的intent)包裝Intent。最后使用setRepeating()方法設置鬧鐘。
至此,對AlarmManager的使用基本結束。用戶設置完鬧鐘時間之后,就是靜靜等待鬧鐘時間的到來。。。然后跳轉到廣播接收器進行下一步的操作。
源代碼地址:https://github.com/hust-MC/ShakeAlarm
APK地址:http://yun.baidu.com/share/link?shareid=479604504&uk=67973003
未來待續(xù)。。。。