定时器相信大家都不陌生,我们可以在固定的时间做某件事,也可以在固定的时间段重复做某件事,今天就来分析一下java中自带的定时任务器Timer。Timer类的作用是是负责计划任务的功能,也就是在指定的时间开始执行某一个任务。Timer类的主要作用是设置计划任务,但封装任务的类却是TimerTask类。
一.基本使用
项目需求:开启定时任务,每一秒更新一下TextView。
代码
public class TimerActivity extends AppCompatActivity {
private TextView textView;
private Timer timer;
private int count = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_timer);
textView = findViewById(R.id.activity_timer_textview);
timer = new Timer();
timer.schedule(new task(), 0, 1000);//立刻开始,每1秒执行一次
}
/**
* TimerTask继承类
*/
private class task extends TimerTask {
@Override
public void run() {
count++;
Log.d("TAG", "count----:" + count);
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText("count:" + count);
}
});
}
}
/**
* onDestroy方法
*/
@Override
protected void onDestroy() {
super.onDestroy();
if (null != timer) {
timer.cancel();
}
}
}
结果
10:06:54.044 D/TAG: count----:1
10:06:55.044 D/TAG: count----:2
10:06:56.045 D/TAG: count----:3
10:06:57.044 D/TAG: count----:4
10:06:58.045 D/TAG: count----:5
10:06:59.046 D/TAG: count----:6
10:07:00.046 D/TAG: count----:7
10:07:01.047 D/TAG: count----:8
10:07:02.047 D/TAG: count----:9
10:07:03.048 D/TAG: count----:10
10:07:04.048 D/TAG: count----:11
10:07:05.048 D/TAG: count----:12
10:07:06.049 D/TAG: count----:13
10:07:07.048 D/TAG: count----:14
10:07:08.048 D/TAG: count----:15
10:07:09.048 D/TAG: count----:16
10:07:10.048 D/TAG: count----:17
10:07:11.049 D/TAG: count----:18
10:07:12.049 D/TAG: count----:19
10:07:13.049 D/TAG: count----:20
10:07:14.050 D/TAG: count----:21
在上述基础上指定时间执行。
代码
public class TimerActivity extends AppCompatActivity {
private TextView textView;
private Timer timer;
private int count = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_timer);
textView = findViewById(R.id.activity_timer_textview);
timer = new Timer();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String string = "2018-05-30 09:28:30";
try {
Date date = simpleDateFormat.parse(string);
timer.schedule(new task(), date, 2000);//string执行 每2秒执行一次
Log.d("TAG", "当前时间----:" + new Date().toLocaleString() + "----任务时间:" + date.toLocaleString());
} catch (ParseException e) {
e.printStackTrace();
}
}
/**
* TimerTask继承类
*/
private class task extends TimerTask {
@Override
public void run() {
count++;
Log.d("TAG", "count----:" + count);
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText("count:" + count);
}
});
}
}
/**
* onDestroy方法
*/
@Override
protected void onDestroy() {
super.onDestroy();
if (null != timer) {
timer.cancel();
}
}
}
结果
<1> Date时间 即指定执行时间(晚于当前时间)
任务会等待到指定的时间,指定时间一到任务就开始执行。
<2> Date时间 即 指定执行时间(早于当前时间)
任务会立刻执行
二.重点讲解
1.TimerTask任务队列是排队运行的,下面讲述如何清除任务队列。这里用到cancel方法,而TimerTask和Timer都有cancel的方法。
<1> TimerTask.cancel():将自身从任务队列中清除。
代码
private class MyTimerTask1 extends TimerTask {
@Override
public void run() {//正式使用 一般Handler通讯
count++;
Log.d("TAG", "MyTimerTask111开始执行运行时间----:" + new Date().toLocaleString() + "----count:" + count);
this.cancel();
}
}
private class MyTimerTask2 extends TimerTask {
@Override
public void run() {//正式使用 一般Handler通讯
count++;
Log.d("TAG", "MyTimerTask222开始执行运行时间----:" + new Date().toLocaleString() + "----count:" + count);
}
}
结果
可以看出MyTimerTask1执行了自己的cancel方法,而MyTimerTask2没有执行自己的cancel方法,所以MyTimerTask1的run方法执行了一次就不再执行,而MyTimerTask2则循环执行。
<2> Timer.cancel():将任务队列中的全部任务清空。
代码
if (null != timer) {
timer.cancel();
}
结果
2.schedule方法与scheduleAtFixedRate方法
<1> 延时XXX秒执行 每XXX秒执行一次
代码
timer = new Timer();
timer.schedule(new MyTimerTask1(),5000,2000);//延时5秒执行 每2秒执行一次
结果
代码
timer = new Timer();
timer.scheduleAtFixedRate(new MyTimerTask1(),5000,2000);//延时5秒执行 每2秒执行一次
结果
也就是说 两个方法 都用 long l1,long l2 参数时没区别。
<2> 指定时间执行 (制定执行时间晚于当前时间)
代码
timer = new Timer();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String string = "2018-05-30 10:32:30";
try {
Date date = simpleDateFormat.parse(string);
timer.schedule(new MyTimerTask1(), date, 2000);//string执行 每2秒执行一次
Log.d("TAG", "当前时间----:" + new Date().toLocaleString() + "----任务执行时间:" + date.toLocaleString());
} catch (ParseException e) {
e.printStackTrace();
}
结果
代码
timer = new Timer();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String string = "2018-05-30 10:36:30";
try {
Date date = simpleDateFormat.parse(string);
timer.scheduleAtFixedRate(new MyTimerTask1(), date, 2000);//string执行 每2秒执行一次
Log.d("TAG", "当前时间----:" + new Date().toLocaleString() + "----任务执行时间:" + date.toLocaleString());
} catch (ParseException e) {
e.printStackTrace();
}
结果
也就是说都用 Date date,long l 参数时 date晚于当前时间也没区别。
<3> 指定时间执行 (制定执行时间早于当前时间)
过一会在执行使以上2018-05-30 10:32:30 和 2018-05-30 10:36:30 过时再分别运行
schedule方法执行结果
scheduleAtFixedRate方法执行结果
也就是说当设定的时间早于当前时间时就有区别了。
schedule方法:如果执行任务的时间没有被延时,那么下次任务的执行时间是参考上一次任务的开始时间来计算的。
scheduleAtFixedRate方法:如果执行任务的时间没有被延时,那么下次执行任务的时间是参考上一次任务的结束时间来开始计算的。
3.Timer构造方法
<1> public Timer()
创建一个新计时器。相关的线程不作为守护程序运行。
<2> public Timer(boolean isDaemon)
创建一个新计时器,可以指定其相关的线程作为守护程序运行。如果计时器将用于安排重复的“维护活动”,则调用守护线程,在应用程序运行期间必须调用守护线程,但是该操作不应延长程序的生命周期。
补充:
守护进程(daemon)是一类在后台运行的特殊进程,用于执行特定的系统任务。很多守护进程在系统引导的时候启动,并且一直运行直到系统关闭。另一些只在需要的时候才启动,完成任务后就自动结束。
守护进程是一个在后台运行并且不受任何终端控制的进程。
<3> public Timer(String name)
创建一个新计时器,其相关的线程具有指定的名称。相关的线程不作为守护程序运行。
参数:
name - 相关线程的名称。
抛出:
NullPointerException - 如果name 为null。
4.Timer常用方法
<1> public void schedule(TimerTask task,long delay)
安排在指定延迟后执行指定的任务。
参数:
task - 所要安排的任务。
delay - 执行任务前的延迟时间,单位是毫秒。
抛出:
IllegalArgumentException - 如果delay 是负数, 或者delay +System.currentTimeMillis() 是负数。
IllegalStateException - 如果已经安排或取消了任务,或者已经取消计时器。
<2> public void schedule(TimerTask task,Date time)
安排在指定的时间执行指定的任务。如果此时间已过去,则安排立即执行该任务。
参数:
task - 所要安排的任务。
time - 执行任务的时间。
抛出:
IllegalArgumentException - 如果time.getTime() 是负数。
IllegalStateException - 如果已经安排或取消了任务,已经取消了计时器,或者计时器线程已终止。
<3> public void schedule(TimerTask task,long delay,long period)
安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。以近似固定的时间间隔(由指定的周期分隔)进行后续执行。在固定延迟执行中,根据前一次执行的实际执行时间来安排每次执行。如果由于任何原因(如垃圾回收或其他后台活动)而延迟了某次执行,则后续执行也将被延迟。从长期来看,执行的频率一般要稍慢于指定周期的倒数(假定Object.wait(long) 所依靠的系统时钟是准确的)。固定延迟执行适用于那些需要“平稳”运行的重复活动。换句话说,它适用于在短期运行中保持频率准确要比在长期运行中更为重要的活动。这包括大多数动画任务,如以固定时间间隔闪烁的光标。这还包括为响应人类活动所执行的固定活动,如在按住键时自动重复输入字符。
参数:
task - 所要安排的任务。
delay - 执行任务前的延迟时间,单位是毫秒。
period - 执行各后续任务之间的时间间隔,单位是毫秒。
抛出:
IllegalArgumentException - 如果delay 是负数, 或者delay +System.currentTimeMillis() 是负数。
IllegalStateException - 如果已经安排或取消了任务,已经取消了计时器,或者计时器线程已终止。
<4> public void schedule(TimerTask task,Date firstTime,long period)
安排指定的任务在指定的时间开始进行重复的固定延迟执行。以近似固定的时间间隔(由指定的周期分隔)进行后续执行。在固定延迟执行中,根据前一次执行的实际执行时间来安排每次执行。如果由于任何原因(如垃圾回收或其他后台活动)而延迟了某次执行,则后续执行也将被延迟。在长期运行中,执行的频率一般要稍慢于指定周期的倒数(假定Object.wait(long) 所依靠的系统时钟是准确的)。固定延迟执行适用于那些需要“平稳”运行的重复执行活动。换句话说,它适用于在短期运行中保持频率准确要比在长期运行中更为重要的活动。这包括大多数动画任务,如以固定时间间隔闪烁的光标。这还包括为响应人类活动所执行的固定活动,如在按住键时自动重复输入字符。
参数:
task - 所要安排的任务。
firstTime - 首次执行任务的时间。
period - 执行各后续任务之间的时间间隔,单位是毫秒。
抛出:
IllegalArgumentException - 如果time.getTime() 是负数。
IllegalStateException - 如果已经安排或取消了任务,已经取消了计时器,或者计时器线程已终止。
<5> public int purge()
从此计时器的任务队列中移除所有已取消的任务。调用此方法对计时器的行为没有影响,但是将无法引用队列中已取消的任务。如果没有对这些任务的外部引用,则它们就成为垃圾回收的合格对象。多数程序无需调用此方法。它设计用于一些罕见的应用程序,这些程序可取消大量的任务。调用此方法要以时间来换取空间:此方法的运行时可能与n + c log n 呈正比,其中n 是队列中的任务数,而c 是取消的任务数。注意,从此计时器上所安排的任务中调用此方法是允许的。
返回:
从队列中移除的任务数。
<6> public void scheduleAtFixedRate(TimerTask task,long delay,long period)
安排指定的任务在指定的延迟后开始进行重复的固定速率执行。以近似固定的时间间隔(由指定的周期分隔)进行后续执行。在固定速率执行中,根据已安排的初始执行时间来安排每次执行。如果由于任何原因(如垃圾回收或其他背景活动)而延迟了某次执行,则将快速连续地出现两次或更多的执行,从而使后续执行能够“追赶上来”。从长远来看,执行的频率将正好是指定周期的倒数(假定Object.wait(long)所依靠的系统时钟是准确的)。固定速率执行适用于那些对绝对时间敏感的重复执行活动,如每小时准点打钟报时,或者在每天的特定时间运行已安排的维护活动。它还适用于那些完成固定次数执行的总计时间很重要的重复活动,如倒计时的计时器,每秒钟滴答一次,共10 秒钟。最后,固定速率执行适用于安排多个重复执行的计时器任务,这些任务相互之间必须保持同步。
参数:
task - 所要安排的任务。
delay - 执行任务前的延迟时间,单位是毫秒。
period - 执行各后续任务之间的时间间隔,单位是毫秒。
抛出:
IllegalArgumentException - 如果delay 是负数, 或者delay +System.currentTimeMillis() 是负数。
IllegalStateException - 如果已经安排或取消了任务,已经取消了计时器,或者计时器线程已终止。
<7> public void scheduleAtFixedRate(TimerTask task,Date firstTime,long period)
安排指定的任务在指定的时间开始进行重复的固定速率执行。以近似固定的时间间隔(由指定的周期分隔)进行后续执行。在固定速率执行中,相对于已安排的初始执行时间来安排每次执行。如果由于任何原因(如垃圾回收或其他背景活动)而延迟了某次执行,则将快速连续地出现两次或更多次执行,从而使后续执行能够赶上来。从长远来看,执行的频率将正好是指定周期的倒数(假定Object.wait(long) 所依靠的系统时钟是准确的)。固定速率执行适用于那些对绝对时间敏感的重复执行活动,如每小时准点打钟报时,或者在每天的特定时间运行已安排的维护活动。它还适用于那些完成固定次数执行的总计时间很重要的重复活动,如倒计时的计时器,每秒钟滴答一次,共10 秒钟。最后,固定速率执行适用于安排多次重复执行的计时器任务,这些任务相互之间必须保持同步。
参数:
task - 所要安排的任务。
firstTime - 首次执行任务的时间。
period - 执行各后续任务之间的时间间隔,单位是毫秒。
抛出:
IllegalArgumentException - 如果time.getTime() 是负数。
IllegalStateException - 如果已经安排或取消了任务,已经取消了计时器,或者计时器线程已终止。