Android個性鬧鐘—搖搖醒

花了一周時間突發(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ù)。。。。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容