TShopping

 找回密碼
 註冊
搜索
查看: 187|回復: 0

[教學] Android 定時通知 AlarmManager 使用

[複製鏈接]
發表於 2020-9-7 23:18:41 | 顯示全部樓層 |閱讀模式
 
Push to Facebook Push to Plurk  
本篇使用AlarmManager達到準時執行某程式,跟鬧鐘的方式一樣,我之前用過IntentService、Service、Handler,都不能長期使用。
Servicer簡單缺點整理:
IntentService:只要關閉activity背景保存視窗,IntentService背景所執行的程式就被強迫結束,好像可以重開(我沒試過)。
Service、Handler:雖然關閉activity會繼續執行,但他是重新在開啟一次service,這到還好,但當手機螢幕關閉處於待機狀態時,service會停止運作暫停在那邊,等你喚醒再繼續執行,所以用這個加timer做定時通知會整個亂掉,timer會停下來不數了。

AlarmManager主要架構是
跟系統註冊鬧鐘甚麼時間點 → 時間到系統會發送一個鬧鈴 → 你的activity接收那個鬧鈴後執行你的程式
當你註冊好幾個鬧鐘已經晚於現在時間,他會馬上通通都執行完

先建立接收鬧鈴的程式
在Manifest.xml 中加入接收系統鬧鈴
  1. <application>
  2.     <activity
  3.         android:name=".MainActivity">
  4.     </activity>
  5.     <!-- 當鬧鈴時間到達時要執行的程式 -->
  6.     <receiver android:name=".AlarmReceiver">
  7.         <intent-filter>
  8.             <action android:name="activity_app" />
  9.         </intent-filter>
  10.     </receiver>

  11. </application>
複製代碼

建立一個class檔,執行接收到鬧鈴後的程式

AlarmManager AlarmReceiver receiver

AlarmManager AlarmReceiver receiver


  1. public class AlarmReceiver extends BroadcastReceiver {
  2.     @Override
  3.     public void onReceive(Context context, Intent intent) {
  4.    
  5.         Bundle bData = intent.getExtras();
  6.         if(bData.get("title").equals("activity_app"))
  7.         {
  8.             //主要執行的程式
  9.         }
  10.     }
  11. }
  12. 註冊和取消鬧鐘
  13. /***    加入(與系統註冊)鬧鐘    ***/
  14. public static void add_alarm(Context context, Calendar cal) {
  15.     Log.d(TAG, "alarm add time: " + String.valueOf(cal.get(Calendar.MONTH)) + "." + String.valueOf(cal.get(Calendar.DATE)) + " " + String.valueOf(cal.get(Calendar.HOUR_OF_DAY)) + ":" + cal.get(Calendar.MINUTE) + ":" + cal.get(Calendar.SECOND));

  16.     Intent intent = new Intent(context, AlarmReceiver.class);
  17.     // 以日期字串組出不同的 category 以添加多個鬧鐘
  18.     intent.addCategory("ID." + String.valueOf(cal.get(Calendar.MONTH)) + "." + String.valueOf(cal.get(Calendar.DATE)) + "-" + String.valueOf((cal.get(Calendar.HOUR_OF_DAY) )) + "." + String.valueOf(cal.get(Calendar.MINUTE)) + "." + String.valueOf(cal.get(Calendar.SECOND)));
  19.     String AlarmTimeTag = "Alarmtime " + String.valueOf(cal.get(Calendar.HOUR_OF_DAY)) + ":" + String.valueOf(cal.get(Calendar.MINUTE)) + ":" + String.valueOf(cal.get(Calendar.SECOND));

  20.     intent.putExtra("title", "activity_app");
  21.     intent.putExtra("time", AlarmTimeTag);

  22.     PendingIntent pi = PendingIntent.getBroadcast(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);

  23.     AlarmManager am = (AlarmManager) context.getSystemService(ALARM_SERVICE);
  24.     am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pi);       //註冊鬧鐘
  25. }

  26. /***    取消(與系統註冊的)鬧鐘    ***/
  27. private static void cancel_alarm(Context context, Calendar cal) {
  28.     Log.d(TAG, "alarm cancel time: " + String.valueOf(cal.get(Calendar.MONTH)) + "." + String.valueOf(cal.get(Calendar.DATE)) + " " + String.valueOf(cal.get(Calendar.HOUR_OF_DAY)) + ":" + cal.get(Calendar.MINUTE) + ":" + cal.get(Calendar.SECOND));

  29.     Intent intent = new Intent(context, AlarmReceiver.class);
  30.     // 以日期字串組出不同的 category 以添加多個鬧鐘
  31.     intent.addCategory("ID." + String.valueOf(cal.get(Calendar.MONTH)) + "." + String.valueOf(cal.get(Calendar.DATE)) + "-" + String.valueOf((cal.get(Calendar.HOUR_OF_DAY) )) + "." + String.valueOf(cal.get(Calendar.MINUTE)) + "." + String.valueOf(cal.get(Calendar.SECOND)));
  32.     String AlarmTimeTag = "Alarmtime " + String.valueOf(cal.get(Calendar.HOUR_OF_DAY)) + ":" + String.valueOf(cal.get(Calendar.MINUTE)) + ":" + String.valueOf(cal.get(Calendar.SECOND));

  33.     intent.putExtra("title", "activity_app");
  34.     intent.putExtra("time", AlarmTimeTag);

  35.     PendingIntent pi = PendingIntent.getBroadcast(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);

  36.     AlarmManager am = (AlarmManager) context.getSystemService(ALARM_SERVICE);
  37.     am.cancel(pi);    //取消鬧鐘,只差在這裡
  38. }
複製代碼


當 AlarmManager 執行 set() 時,Android 系統會比對已註冊的其他 Intent 的 action、data、type、class、category,如果這幾個屬性完全相同,則系統會將這兩個 Intent 視為一樣,這時系統會視 PendingIntent.FLAG???? 參數以決定如何處理這個新註冊的 Intent。原文

如何呼叫此函式
  1. //下一分鐘0秒時
  2. Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT+8:00")); //取得時間
  3. cal.add(Calendar.MINUTE, 1);    //加一分鐘
  4. cal.set(Calendar.SECOND, 0);    //設定秒數為0
  5. add_alarm(context, cal);        //註冊鬧鐘
  6. //在MainActivity中 context = this
  7. //在service中      context = context(service的)
複製代碼
  1. //註冊多個,每分鐘響共10次
  2. Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT+8:00")); //取得時間
  3. for(int i = 0; i < 10; i++){
  4.     cal.add(Calendar.MINUTE, 1);    //加一分鐘
  5.     cal.set(Calendar.SECOND, 0);    //設定秒數為0
  6.     add_alarm(context, cal);        //註冊鬧鐘
  7. }
  8. //在MainActivity中 context = this
  9. //在service中      context = context(service的)
複製代碼
也可以在AlarmReceiver 中註冊下一個鬧鐘,也就是說當第一個響起,註冊下一個



如果要每間隔一個小時發出提醒


改寫
  1. public static void add_alarm(Context context) {
  2.         final long ALARM_TRIGGER_AT_TIME = SystemClock.elapsedRealtime() + 10000;
  3.         final long ALARM_INTERVAL = 1000 * 60 * 60 ;
  4.         Intent intent = new Intent(context, AlarmReceiver.class);
  5.         intent.putExtra("title", "activity_app");
  6.         PendingIntent pi = PendingIntent.getBroadcast(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
  7.         AlarmManager am = (AlarmManager) context.getSystemService(ALARM_SERVICE);
  8.         am.setRepeating(AlarmManager.RTC_WAKEUP,ALARM_TRIGGER_AT_TIME, ALARM_INTERVAL,pi); //註冊鬧鐘
  9.     }
複製代碼


參考文章
https://xiang1023.blogspot.com/2017/11/android-alarmmanager.html

 

臉書網友討論
您需要登錄後才可以回帖 登錄 | 註冊 |

本版積分規則



Archiver|手機版|小黑屋|免責聲明|TShopping

GMT+8, 2020-9-20 18:21 , Processed in 0.059550 second(s), 24 queries .

本論壇言論純屬發表者個人意見,與 TShopping綜合論壇 立場無關 如有意見侵犯了您的權益 請寫信聯絡我們。

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回復 返回頂部 返回列表