android週期性任務

通常任務調度機制的實現方式主要有: Thread sleep、Timer、ScheduledExecutor、Handler和其餘第三方開源庫、android的AlarmManagerjava

一、 Timerandroid

  java.util.Timer是Java語言自己提供的一種最簡單實現任務調度的方法,使用簡單,經過對應的api調用便可。Timer 設計核心是一個TaskQueue和一個TaskThread。api

Timer將接收到的任務丟到本身的 TaskQueue中,TaskQueue按照Task的最初執行時間進行排序。TimerThread 在建立 Timer 時會啓動成爲一個守護線程,這個守護線程網絡

會輪詢全部任務,找到一個最近要執行的任務,而後休眠,當到達最近要執行任務的開始時間點,TimerThread 被喚醒並執行該任務。以後 TimerThread 更新最近一個要併發

執行的任務,繼續休眠。
  ide

 1 public class PeriodOperation{
 2 
 3     public static void main(String[] args) { 4  testTimer(); 5  } 6 7 private static void testTimer(){ 8 Timer timer = new Timer(); 
9 long delay1 = 1 * 1000; 10 long period1 = 1000; 11 // 從如今開始 1 秒鐘以後,每隔 1 秒鐘執行一次 job1 12 timer.schedule(new TimerTask1("job1"), delay1, period1);

13     long delay2 = 2 * 1000; 14 long period2 = 2000; 15 // 從如今開始 2 秒鐘以後,每隔 2 秒鐘執行一次 job2 16 timer.schedule(new TimerTask1("job2"), delay2, period2); 17 } 18 19 static class TimerTask1 extends TimerTask{ 20 private String jobName = ""; 21 public TimerTask1(String job) { 22 super(); 23 this.jobName = job; 24 } 25 @Override 26 public void run() { 27 System.out.println("執行做業:" + jobName); 28 } 29 } 30 }

  Timer機制實現任務調度的核心類是 Timer 和 TimerTask。其中 Timer 負責設定 TimerTask 的起始與間隔執行時間。使用者只須要建立一個 TimerTask 的繼承類,實現本身的 run 方法,工具

而後將其丟給 Timer 去執行便可。post

  Timer 優勢在於簡單易用,但因爲全部任務都是由同一個線程來調度,所以全部任務都是串行執行的,同一時間只能有一個任務在執行,前一個任務的延遲或異常都將會影響到以後的優化

任務,因此不太適合併發類的任務調度,其實基本上就用不了。ui

二、ScheduledExecutor

  爲了解決Timer 設計上的缺陷,在Java 5推出了基於線程池設計的 ScheduledExecutor。其設計思想是:每個被調度的任務都會由線程池中一個線程去執行,所以任務是併發執行的,

相互之間不會受到干擾。但須要注意的是隻有當任務的執行時間到來時,ScheduedExecutor 纔會真正啓動一個線程,其他時間ScheduledExecutor 都是在輪詢任務的狀態。

 1 import java.text.SimpleDateFormat;
 2 import java.util.Date; 3 import java.util.Timer; 4 import java.util.TimerTask; 5 import java.util.concurrent.Executors; 6 import java.util.concurrent.ScheduledExecutorService; 7 import java.util.concurrent.TimeUnit; 8 9 public class PeriodOperation { 10 11 public static void main(String[] args) { 12  testScheduledExecutor(); 13  } 14 15 private static void testScheduledExecutor(){ 16 ScheduledExecutorService service = Executors.newScheduledThreadPool(10); 17 18 long initialDelay1 = 1; 19 long period1 = 1; 20 // 從如今開始1秒鐘以後,每隔1秒鐘執行一次job1 21 service.scheduleAtFixedRate(new Task1("job1"), initialDelay1, period1, TimeUnit.SECONDS); 22 23 long initialDelay2 = 1; 24 long delay2 = 1; 25 // 從如今開始2秒鐘以後,每隔2秒鐘執行一次job2 26 service.scheduleWithFixedDelay(new Task1("job2"), initialDelay2, delay2, TimeUnit.SECONDS); 27  } 28 29 static class Task1 implements Runnable{ 30 private String jobName = ""; 31 32 public Task1 (String jobName) { 33 super(); 34 this.jobName = jobName; 35  } 36 37 @Override 38 public void run() { 39 System.out.println(getNowTime()+"執行做業:" + jobName); 40 } 41  } 42 43 public static String getNowTime(){ 44 Date now = new Date(); 45 SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); 46 return dateFormat.format(now); 47  } 48 49 }

ScheduledExecutorService 中兩種最經常使用的調度方法 ScheduleAtFixedRate 和 ScheduleWithFixedDelay。

其中ScheduleAtFixedRate 每次執行時間爲上一次任務開始起向後推一個時間間隔,即每次執行時間爲:  initialDelay,  initialDelay+period,  initialDelay+2*period, …;

而ScheduleWithFixedDelay 每次執行時間爲上一次任務結束起向後推一個時間間隔,即每次執行時間爲:initialDelay, initialDelay+executeTime+delay, initialDelay+2*executeTime+2*delay。

因此兩種方式異同在於ScheduleAtFixedRate 是基於固定時間間隔進行任務調度,ScheduleWithFixedDelay 取決於每次任務執行的時間長短,是基於不固定時間間隔進行任務調度。

三、 Handler機制

  以上兩種方式都是由Java語言提供的機制,其實Android 自己也提供了本身的機制。android和AlarmManager都是android提供的。

Handler的postDelayed方法和removeCallbacksAndMessages靈活實現的一種所謂的週期性任務調度,固然也能夠藉助其餘機制來實現開啓和中止,一切取決於你的需求。

四、AlarmManager

  Alarm超出了應用程序的做用域,因此它們能夠用於觸發應用程序事件或動做,甚至在應用程序關閉以後。與Broadcast Receiver結合,它們能夠變得尤爲的強大,能夠經過設置Alarm來啓動應用程序或者執行動做,而應用程序不須要打開或者處於活躍狀態。舉個例子,你能夠使用Alarm來實現一個鬧鐘程序,執行正常的網絡查詢,或者在「非高峯」時間安排耗時或有代價的操做。 

對於僅在應用程序生命週期內發生的定時操做,Handler類與Timer和Thread類的結合是一個更好的選擇,它容許Android更好地控制系統資源。 

Android中的Alarm在設備處於睡眠模式時仍保持活躍,它能夠設置來喚醒設備。然而,全部的Alarm在設備重啓時都會被取消。

AlarmManager設置後不許確的問題:以下爆出的問題

  

11-22 06:05:31.251 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 06:45:05,1970-01-01 08:39:29
11-22 06:05:31.272 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 06:45:05,1970-01-01 08:39:29
11-22 06:05:31.784 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 06:45:05,1970-01-01 08:39:29
11-22 06:05:31.797 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 06:45:05,1970-01-01 08:39:29
11-22 06:45:05.822 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 07:00:05,1970-01-01 08:14:55
11-22 06:45:06.108 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 07:00:05,1970-01-01 08:14:54
11-22 07:05:31.276 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 07:45:05,1970-01-01 08:39:29
11-22 07:05:31.605 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 07:45:05,1970-01-01 08:39:29
11-22 07:45:05.637 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 08:00:05,1970-01-01 08:14:55
11-22 07:45:06.092 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 08:00:05,1970-01-01 08:14:54
11-22 08:05:31.269 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 08:45:05,1970-01-01 08:39:29
11-22 08:05:31.632 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 08:45:05,1970-01-01 08:39:28
11-22 08:45:05.022 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 09:00:05,1970-01-01 08:14:54
11-22 08:45:05.482 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 09:00:05,1970-01-01 08:14:54
11-22 09:05:31.261 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 09:45:05,1970-01-01 08:39:28
11-22 09:05:31.614 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 09:45:05,1970-01-01 08:39:28
11-22 09:45:05.019 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 10:00:05,1970-01-01 08:14:54
11-22 09:45:05.474 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 10:00:05,1970-01-01 08:14:54
11-22 10:05:31.255 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 10:45:05,1970-01-01 08:39:28
11-22 10:05:31.610 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 10:45:05,1970-01-01 08:39:28
11-22 10:45:05.031 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 11:00:05,1970-01-01 08:14:54
11-22 10:45:10.845 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 11:00:05,1970-01-01 08:14:49
11-22 10:55:57.534 28276-28276/com.xxx.fresh D/Linghu DuringService.onStartCommand: ==============AM during=2018-11-22 11:00:05,1970-01-01 08:04:02

11-22 06:05:31.260 28146-28146/com.xxx.card D/Linghu DuringReceiver.onReceive: =========DuringReceiver course2018-11-22 06:05:31
11-22 06:45:05.817 28146-28146/com.xxx.card D/Linghu DuringReceiver.onReceive: =========DuringReceiver course2018-11-22 06:45:05
11-22 07:05:31.251 28146-28146/com.xxx.card D/Linghu DuringReceiver.onReceive: =========DuringReceiver course2018-11-22 07:05:31
11-22 07:45:05.629 28146-28146/com.xxx.card D/Linghu DuringReceiver.onReceive: =========DuringReceiver course2018-11-22 07:45:05
11-22 08:05:31.251 28146-28146/com.xxx.card D/Linghu DuringReceiver.onReceive: =========DuringReceiver course2018-11-22 08:05:31
11-22 08:45:05.013 28146-28146/com.xxx.card D/Linghu DuringReceiver.onReceive: =========DuringReceiver course2018-11-22 08:45:05
11-22 09:05:31.249 28146-28146/com.xxx.card D/Linghu DuringReceiver.onReceive: =========DuringReceiver course2018-11-22 09:05:31
11-22 09:45:05.012 28146-28146/com.xxx.card D/Linghu DuringReceiver.onReceive: =========DuringReceiver course2018-11-22 09:45:05
11-22 10:05:31.246 28146-28146/com.xxx.card D/Linghu DuringReceiver.onReceive: =========DuringReceiver course2018-11-22 10:05:31
11-22 10:45:05.017 28146-28146/com.xxx.card D/Linghu DuringReceiver.onReceive: =========DuringReceiver course2018-11-22 10:45:05
11-22 11:00:05.017 28146-28146/com.xxx.card D/Linghu DuringReceiver.onReceive: =========DuringReceiver course2018-11-22 11:00:05

是由於manager.set(AlarmManager.RTC_WAKEUP, triggerAtTime, pIntent);在android的高版本上回由於android系統的優化、睡眠緣由變得不靈敏,高版本須要使用setExact()就能夠。

 1     AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
 2         Intent repeatIntent = new Intent(this, DuringReceiver.class); 3  repeatIntent.setAction(ACTION_DURING_RECEIVER_COURSE); 4 PendingIntent pIntent = PendingIntent.getBroadcast(this, 1000, repeatIntent, 0); 5 long triggerAtTime = System.currentTimeMillis() + nextDiffTime + 2000; 6 L.d("==============Alarm:" + FormatUtilsKt.getDataAllFormatTime(triggerAtTime) +",nextDiff:"+ FormatUtilsKt.getHhMmTime(nextDiffTime)); 7 8 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { //4.4以上 API19 9  manager.setExact(AlarmManager.RTC_WAKEUP, triggerAtTime, pIntent); 10 }else{ 11  manager.set(AlarmManager.RTC_WAKEUP, triggerAtTime, pIntent); 12 }

 

五、開源工具包 Quartz 與 JCronTab 提供了這方面強大的支持

相關文章
相關標籤/搜索