菜鳥入坑記——第一篇 關鍵字:AlarmManager 一、AlarmManager簡介: 參考網址:https://www.jianshu.com/p/8a2ce9d02640 參考網站:https://www.runoob.com/w3cnote/android-tutorial-alarmma ...
菜鳥入坑記——第一篇
關鍵字:AlarmManager
一、AlarmManager簡介:
參考網址:https://www.jianshu.com/p/8a2ce9d02640
參考網站:https://www.runoob.com/w3cnote/android-tutorial-alarmmanager.html
推薦此網址:https://www.jianshu.com/p/d69a90bc44c0
瞭解android低電耗模式:https://developer.android.google.cn/training/monitoring-device-state/doze-standby.html
AlarmManager的作用:在特定的時刻為我們廣播一個指定的Intent。
即:自己設定一個時間,當系統時間到達此時間時,AlarmManager自動廣播一個我們設定好的Intent,指向某個Activity或Service。
註意:① AlarmManager主要用來在某個時刻運行你的代碼,即使你的APP在那個特定的時間並沒有運行。
二、獲得AlarmManager實例對象:
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
三、方法:
setExact(int type, long startTime, PendingIntent pi); 一次性鬧鐘,執行時間精確,為精確鬧鐘
參數解釋:此部分參考網站https://www.jianshu.com/p/8a2ce9d02640
四、程式設計:
(1)類型type
此處選用鬧鐘類型為AlarmManager.RTC:鬧鐘在睡眠狀態下不可用,該狀態下鬧鐘使用絕對時間(當前系統時間),狀態值為1。
(2)開始時間startTime
由於通過SP獲得的時間為String類型,需先轉換為long類型,且時間單位為ms
1 /** 2 * String類型轉換成date類型 3 * strTime: 要轉換的string類型的時間, 4 * formatType: 要轉換的格式yyyy-MM-dd HH:mm:ss 5 * //yyyy年MM月dd日 HH時mm分ss秒, 6 * strTime的時間格式必須要與formatType的時間格式相同 7 */ 8 public static Date stringToDate(String strTime, String formatType){ 9 KLog.d("進入stringToDate"); 10 try { 11 SimpleDateFormat formatter = new SimpleDateFormat(formatType); 12 Date date = null; 13 date = formatter.parse(strTime); 14 return date; 15 }catch (Exception e){ 16 return null; 17 } 18 } 19 /** 20 * String類型轉換為long類型 21 * ............................. 22 * strTime為要轉換的String類型時間 23 * formatType時間格式 24 * formatType格式為yyyy-MM-dd HH:mm:ss//yyyy年MM月dd日 HH時mm分ss秒 25 * strTime的時間格式和formatType的時間格式必須相同 26 */ 27 public static long stringToLong (String strTime,String formatType){ 28 KLog.d("進入stringToLong"); 29 try{ 30 //String類型轉換為date類型 31 Date date = stringToDate(strTime, formatType); 32 Log.d(TAG,"調用stringToDate()獲得的date:" + date); 33 if (date == null) { 34 return 0; 35 }else { 36 //date類型轉成long類型 37 long Hour = date.getHours(); 38 long Min = date.getMinutes(); 39 long TimeLong = Hour*60*60*1000 + Min*60*1000; 40 Log.d(TAG,"stringToLong()獲得的Hour:" + Hour + " h"); 41 Log.d(TAG,"stringToLong()獲得的Min:" + Min + " min"); 42 Log.d(TAG,"stringToLong()獲得的TimeLong:" + TimeLong + " ms"); 43 return TimeLong; 44 } 45 }catch (Exception e){ 46 return 0; 47 } 48 }
Java Date、String、Long三種日期類型之間的相互轉換
參考網址:http://www.blogjava.net/weishuangshuang/archive/2012/09/27/388712.html
成功獲得睡眠時間(SLEEP_TIME)和起床時間(GET_UP_TIME)(單位ms)之後,計算鎖屏時間IntervalTime(睡眠時間至起床時間):
1 //計算時間間隔 2 if (GET_UP_TIME >= SLEEP_TIME){ 3 IntervalTime = GET_UP_TIME - SLEEP_TIME; 4 }else { 5 IntervalTime = 24*60*60*1000 + GET_UP_TIME - SLEEP_TIME; 6 }
(3)定義跳轉Activity的操作:PendingIntent pi
我們的目的是利用AlarmManager的set()方法讓鬧鐘在我們指定的時間點執行我們自定義的intent操作。這裡時間點的設置非常重要,若時間設置的不精確(一般精確到秒即可,以下代碼中精確至ms),將會導致鬧鐘執行intent有延遲。(SLEEP_TIME_HOUR和SLEEP_TIME_MIN分佈是睡眠時間的小時數和分鐘數)
1 //設置當前的時間 2 Calendar calendar = Calendar.getInstance(); 3 calendar.setTimeInMillis(System.currentTimeMillis()); 4 //根據用戶選擇的時間來設置Calender對象(即:睡覺時間) 5 calendar.set(Calendar.HOUR_OF_DAY, (int)SLEEP_TIME_HOUR); 6 calendar.set(Calendar.MINUTE, (int) SLEEP_TIME_MIN); 7 calendar.set(Calendar.SECOND, 0); 8 calendar.set(Calendar.MILLISECOND,0); 9 //設置當前時區(若時區不對,鬧鐘將有偏差) 10 TimeZone timeZone = TimeZone.getDefault();//獲取系統時間時區 11 KLog.d("當前設置的時區為: " + timeZone); 12 calendar.setTimeZone(timeZone); 13 KLog.d("睡覺時間:" + SLEEP_TIME + "ms, 起床時間:" + GET_UP_TIME + "ms."); 14 KLog.d("夜間休息時長:IntervalTime = " + IntervalTime + "ms.");
定義intent操作:
1 //定義用於跳轉到 LockScreenActivity.class 中的Intent對象intent 2 Intent intent = new Intent(RobotClientMainActivity.this, LockScreenActivity.class); 3 intent.putExtra("INTERVAL", IntervalTime);
putExtra("INTERVAL", IntervalTime); "INTERVAL"為關鍵字,IntervalTime為傳入值(此處指睡眠時鎖屏的時間ms)。帶值跳轉至LockScreenActivity.class中,LockScreenActivity執行相應的鎖屏操作。
初始化鬧鐘的執行操作pi:
PendingIntent.getActivity的使用:https://www.cnblogs.com/lyxin/p/5995681.html
1 //初始化鬧鐘的執行操作pi 2 pi = PendingIntent.getActivity(RobotClientMainActivity.this,0
,intent,PendingIntent.FLAG_UPDATE_CURRENT);
方法:PendingIntent.getActivity(Context context, int requestCode, Intent intent, int flags);
第一個參數是上下文context;
第二個參數是請求碼,用於標識此PendingIntent的對象,相當於關鍵字;
第三個參數是意圖,用於跳轉Activity;
第四個參數代表了PendingIntent的四種不同的狀態,可用理解為狀態標識符。四種狀態如下:
①FLAG_CANCEL_CURRENT:
如果當前系統中已經存在一個相同的PendingIntent對象,則已有的PendingIntent將會取消,然後重新生成一個PendingIntent對象。
②FLAG_NO_CREATE:
如果當前系統中不存在相同的PendingIntent對象,系統將不會創建該PendingIntent對象,而是直接返回null。
③FLAG_ONE_SHOT:
該PendingIntent只作用一次。在該PendingIntent對象通過send()方法觸發過後,PendingIntent將自動調用cancel()進行銷毀,如果你再調用send()方法,系統將會返回一個SendIntentException。
④FLAG_UPDATE_CURRENT:
如果系統中有一個和你描述的PendingIntent對等的PendingIntent,那麼系統將使用該PendingIntent對象,但是會使用新的Intent來更新之前PendingIntent中的Intent對象數據,例如更新Intent中的Extras。
(4)設置alarmManager:
1 //定義AlarmManager對象 2 private AlarmManager alarmManager;
1 //初始化alarmManager 2 alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
1 /** 2 * 設置AlarmManager在Calendar對應的時間啟動Activity 3 * 當到達睡覺時間時跳轉至LockScreenActivity執行鎖屏操作 4 */ 5 alarmManager.setExact(AlarmManager.RTC,calendar.getTimeInMillis(),pi); 6 KLog.d("從calender中讀取到的睡眠時間:" + calendar.getTime() 7 + "/n 毫秒:"+calendar.getTimeInMillis());
在此處,系統已經能夠在指定的時間跳轉至鎖屏操作。但是實踐中出現的問題是:只要系統時間已經超過指定時間,關機重啟時會自動跳入鎖屏操作——為什麼???。。。:( 。。。求大神指導
********************************************************************************************************************************************************************************************************************************************************************************
雖然沒有弄清alarmManager.setExact的機制;但是利用其在實踐中的表現(指過了鎖屏時間重啟後仍會鎖屏),在關鍵時間點加入if/else的判斷,成功實現了功能。
相關條件判斷如下:
定義和初始化部分:
1 //定義睡覺和起床時間單位ms 2 long SLEEP_TIME,GET_UP_TIME; 3 //睡覺和起床時間對應的小時數和分鐘數 4 long SLEEP_TIME_HOUR,SLEEP_TIME_MIN; 5 long GET_UP_TIME_HOUR,GET_UP_TIME_MIN; 6 //定義睡覺時間和起床時間之間的時間間隔 7 long IntervalTime; 8 //定義系統當前時間(單位ms) 9 long CurrentTime_ms;
1 //設置當前的時間 2 Calendar calendar = Calendar.getInstance(); 3 calendar.setTimeInMillis(System.currentTimeMillis()); 4 KLog.d("111系統當前時間為:" + calendar.getTime()); 5 KLog.d("系統當前時間Hour:" + calendar.get(Calendar.HOUR_OF_DAY)); 6 KLog.d("系統當前時間Min:" + calendar.get(Calendar.MINUTE)); 7 KLog.d("系統當前時間Second:" + calendar.get(Calendar.SECOND)); 8 CurrentTime_ms = calendar.get(Calendar.HOUR_OF_DAY)*60*60*1000 9 +calendar.get(Calendar.MINUTE)*60*1000+calendar.get(Calendar.SECOND)*1000;
條件判斷:
1 /** 2 * 計算夜間休息時長 3 * 如果當前時間沒到睡眠時間,則休息時長定為睡眠時間至起床時間 4 * 若果當前時間在睡眠時間和起床時間之間,則休息時長定為當前時間至起床時間 5 */ 6 if (GET_UP_TIME >= SLEEP_TIME) { 7 if ((CurrentTime_ms >= SLEEP_TIME) && (CurrentTime_ms <= GET_UP_TIME)) { 8 IntervalTime = GET_UP_TIME - CurrentTime_ms; 9 10 }else { 11 IntervalTime = GET_UP_TIME - SLEEP_TIME; 12 } 13 }else { 14 if ((CurrentTime_ms <= SLEEP_TIME) && (CurrentTime_ms >= GET_UP_TIME)) { 15 IntervalTime = 24*60*60*1000 + GET_UP_TIME - SLEEP_TIME; 16 }else { 17 if(CurrentTime_ms <= GET_UP_TIME) { 18 IntervalTime = GET_UP_TIME - CurrentTime_ms; 19 }else { 20 IntervalTime = 24*60*60*1000 + GET_UP_TIME - CurrentTime_ms; 21 } 22 } 23 } 24 KLog.d("夜間休息時長:IntervalTime = " + IntervalTime + "ms.");
1 /** 2 * 設置AlarmManager在Calendar對應的時間啟動Activity 3 * 當到達睡覺時間時跳轉至LockScreenActivity執行鎖屏操作 4 * 若系統當前時間已經不屬於夜間休息時間,加入判斷使程式不再調用alarmManager 5 */ 6 if (GET_UP_TIME >= SLEEP_TIME) { 7 if (CurrentTime_ms < GET_UP_TIME) { 8 KLog.d("當前時間 CurrentTime_ms = " + CurrentTime_ms + "ms"); 9 KLog.d("起床時間 GET_UP_TIME = " + GET_UP_TIME + "ms"); 10 alarmManager.setExact(AlarmManager.RTC,calendar.getTimeInMillis(),pi); 11 KLog.d("從calender中讀取到的睡眠時間:" + calendar.getTime() 12 + "/n 毫秒:"+calendar.getTimeInMillis()); 13 } 14 }else { 15 KLog.d("當前時間 CurrentTime_ms = " + CurrentTime_ms + "ms"); 16 KLog.d("起床時間 GET_UP_TIME = " + GET_UP_TIME + "ms"); 17 alarmManager.setExact(AlarmManager.RTC,calendar.getTimeInMillis(),pi); 18 KLog.d("從calender中讀取到的睡眠時間:" + calendar.getTime() 19 + "/n 毫秒:"+calendar.getTimeInMillis()); 20 }
實現功能:在指定時間範圍內對APP鎖屏,在鎖屏時間內,重啟APP仍可鎖屏,不會因重啟而終止整個鎖屏活動。
小結:查閱了N多資料,終於實現了這一功能(*^▽^*),雖然還有許多不懂的地方,但是我會繼續努力的。
最後,大神們給給意見撒。。。