標籤:
畢業設計中有個功能模組叫就醫提醒,大抵的功能就是使用者設定一個未來時間的鬧鐘,並設定鬧鐘的標籤,標籤上寫著去哪裡就醫之類的資訊,主要設計參考魅族系統內建的鬧鐘功能。我在網上看了不少部落格,也在github上下載了不少源碼,發現也沒有寫的特別好的,總有這種或者那種的問題,比如說鬧鐘不是寫成後台服務的模式,APP關閉之後鬧鐘不會提醒,或者手機關機之後之前設定的鬧鐘資訊丟失,所以我準備自己寫一個功能比較齊全的。
所以這個鬧鐘的功能需要用到Android的資料庫Sqlite、Service、BroadcastReceiver三大比較重要的模組,之前在看《第一行代碼》時,由於看的比較匆忙,所以書本後面的部分知識點學習的並不紮實,書中的代碼並沒有親自在IDE中敲一敲,所以藉著五一假期三天又重頭好好看了一遍《第一行代碼》中關於資料庫Sqlite、Service、BroadcastReceiver的部分。
Sqlite是一個輕量級的Android內建資料庫,通常只佔幾百KB的記憶體,所以在行動裝置上也非常的適用。建立資料庫的表如下,並寫了一個Helper類對資料庫操作進行了封裝,簡化了底層操作資料的操作。
1 public class AlarmDBHelper extends SQLiteOpenHelper{ 2 public static final String DATABASE_NAME = "userinfo.db"; 3 public static final int DATABASE_VERSION = 2; 4 public static final String TABLE = "alarm"; 5 6 7 private static final String CREATE_ALARM_TABLE = "CREATE TABLE " + TABLE + " (" 8 + AlarmColumn._ID + " integer primary key AUTOINCREMENT," 9 + AlarmColumn.ALARM_ID + " text UNIQUE ON CONFLICT REPLACE,"10 + AlarmColumn.ALARM_CALENDAR + " text,"11 + AlarmColumn.ALARM_CANCELABLE + " text,"12 + AlarmColumn.ALARM_TAG + " text,"13 + AlarmColumn.ALARM_AVAILABLE + " text,"14 + AlarmColumn.ALARM_RINGTONE + " text)";15 16 public AlarmDBHelper(Context context) {17 super(context, DATABASE_NAME, null, DATABASE_VERSION);18 }19 20 @Override21 public void onCreate(SQLiteDatabase db) {22 db.execSQL(CREATE_ALARM_TABLE);23 }24 25 @Override26 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {27 String sql=" DROP TABLE IF EXISTS "+TABLE;28 db.execSQL(sql);29 onCreate(db);30 }31 }
若要修改原先的資料庫,只需要在 dbHelper = new AlarmDBHelper(this, "userinfo.db", null, 3); 中增加version的版本號碼即可。資料庫的操作無非就是CRUD,C代表添加(Create),R代表查詢(Retrieve),U代表更新(Update),D代表刪除(Delete)。操作基本與SQL相同,同時官方支援使用SQL語句建立資料庫和CRUD。其中查詢資料庫設計到一個新的資料類型——Cursor,本意為游標,可以理解為資料庫中每行的內容。cursor.moveToFirst()移動到表中的第一行,cursor.moveToNext() 即指移動到下一行。上述代碼即建立一個鬧鐘的 table ,將建立鬧鐘所需的一些資訊儲存在資料庫中。
1 public class BootReceiver extends BroadcastReceiver{ 2 @Override 3 public void onReceive(Context context, Intent intent) { 4 ArrayList<Alarm> alarms = getAllAlarms(context); 5 for (Alarm alarm : alarms) { 6 // Test 7 // 當重啟後,所有的都應該恢複,而如果這是定時任務,那麼只要恢複月度和年度的就可以了. 8 // 如果每天00:00重建鬧鐘的話,那麼00:00時響的鬧鐘會不會響呢 9 // 所以最後錯開一點,因為鬧鐘沒有秒數,所以設定為00:00:30秒何如。10 // 不論是什麼鬧鐘,都會保證如果第二天有鬧鐘的話就會設定上的,所以不用擔心00:00的鬧鐘不會設定上11 alarm.activate();12 }13 }14 15 /**16 * 從本機資料庫恢複所有的鬧鐘17 *18 * @return19 */20 private ArrayList<Alarm> getAllAlarms(Context context) {21 AlarmHelper helper = new AlarmHelper(context);22 return helper.getAlarms();23 }24 }
並註冊一個廣播監聽開機的action,每當開機時將所有的alarm從資料庫中都出來,並啟用所有的鬧鐘,即AlarmReceive監聽所有鬧鐘。
1 private void setOneTimeAlarm() { 2 if (AudreyCalendar.getTimeInMillis() - System.currentTimeMillis() > 0) { 3 // 最後一個參數必須是PendingIntent.FLAG_UPDATE_CURRENT,否則BroadcastReceiver將收不到參數。 4 PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 5 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); 6 AlarmManager manager = (AlarmManager) mContext 7 .getSystemService(Context.ALARM_SERVICE); 8 manager.set(AlarmManager.RTC_WAKEUP, 9 AudreyCalendar.getTimeInMillis(), pendingIntent);10 } else {11 Toast.makeText(mContext, "小夥子,設定太早鬧鐘是不會執行滴!",12 Toast.LENGTH_SHORT).show();13 }14 }
通過這樣資料庫中的鬧鐘會在 setOneTimeAlarm() 設定響鈴的時間。AlarmReceive 中的代碼如下,
1 public class AlarmReceiver extends BroadcastReceiver{ 2 3 @Override 4 public void onReceive(Context context, Intent intent) { 5 6 Alarm alarm=new Alarm(context, intent.getExtras()); 7 Intent intent2=new Intent(); 8 intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 9 intent2.setClass(context, RingActivity.class);10 intent2.putExtras(Alarm.alarm2Bundle(alarm));11 context.startActivity(intent2);12 13 14 15 }16 }
通過Receive中的方法啟動RingActivity,觸發響鈴的操作,整個鬧鐘的邏輯就完成了。
按理說,鬧鐘的實現應該通過service實現,這樣就可以使得即使app關閉時,背景鬧鐘也是在啟動並執行,不過如何在service中啟動一個鬧鐘我不知道如何?。整個的邏輯應該是當設定好鬧鐘的屬性,點擊增加鬧鐘時,鬧鐘的資訊被儲存在資料庫中,同時觸發一個service啟動,在service服務中接受alarm中的資訊,設定後一個
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 5 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); 6 AlarmManager manager = (AlarmManager) mContext 7 .getSystemService(Context.ALARM_SERVICE); 8 manager.set(AlarmManager.RTC_WAKEUP, 9 AudreyCalendar.getTimeInMillis(), pendingIntent); 將getBroadcast改成getActivity,跳轉到RingActivity即可實現整個的邏輯。
因My Code借鑒了他人的代碼,導致我在代碼的閱讀中陷入了極大的混亂,同時整個的邏輯也非常的不清晰,造成了代碼工作非常緩慢的事實,此後我必須在閱讀他人的代碼的基礎上理解整個邏輯實現,理清思路,完成自己的設計。
Android學習筆記之AlarmManager有關的定時器和鬧鐘的實現