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 提供了这方面强大的支持

相关文章
相关标签/搜索