android的定时任务
2015-11-28 22:03
585 查看
android的定时任务有两种实现方式:Timer和Alarm机制。
在Android开发中,定时执行任务的3种实现方法:
一、采用Handler与线程的sleep(long)方法(不建议使用,java的实现方式)
二、采用Handler的postDelayed(Runnable, long)方法(最简单的android实现)
三、采用Handler与timer及TimerTask结合的方法(比较多的任务时建议使用)
下面逐一介绍:
一、采用Handle与线程的sleep(long)方法
Handler主要用来处理接受到的消息。这只是最主要的方法,当然Handler里还有其他的方法供实现,有兴趣的可以去查API,这里不过多解释。
1. 定义一个Handler类,用于处理接受到的Message。
[java] view
plaincopy
Handler handler = new Handler() {
public void handleMessage(Message msg) {
// 要做的事情
super.handleMessage(msg);
}
};
2. 新建一个实现Runnable接口的线程类,如下:
[java] view
plaincopy
public class MyThread implements Runnable {
@Override
public void run() {
while (true) {
//不断循环,实现每隔10s发送一次Message
try {
Thread.sleep(10000);// 线程暂停10秒,单位毫秒
Message message = new Message();
message.what = 1;
handler.sendMessage(message);// 发送消息
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
3. 在需要启动线程的地方加入下面语句:
[java] view
plaincopy
new Thread(new MyThread()).start();
4. 启动线程后,线程每10s发送一次消息。
二、采用Handler的postDelayed(Runnable, long)方法
这个实现比较简单一些。
1. 定义一个Handler类
[java] view
plaincopy
Handler handler=new Handler();
Runnable runnable=new Runnable() {
@Override
public void run() {
//要做的事情
handler.postDelayed(this, 2000);
}
};
2. 启动计时器
[java] view
plaincopy
handler.postDelayed(runnable, 2000);//每两秒执行一次runnable.
3. 停止计时器
[java] view
plaincopy
handler.removeCallbacks(runnable);
三、采用Handler与timer及TimerTask结合的方法
1. 定义定时器、定时器任务及Handler句柄
[java] view
plaincopy
private final Timer timer = new Timer();
private TimerTask task;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 要做的事情
super.handleMessage(msg);
}
};
2. 初始化计时器任务
[java] view
plaincopy
task = new TimerTask() {
@Override
public void run() {
// TODO Auto-generated method stub
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
}
};
3. 启动定时器
[java] view
plaincopy
timer.schedule(task, 2000, 2000);
3. 停止计时器
[java] view
plaincopy
timer.cancel();
简要说一下上面三步提到的一些内容:
1. 定时器任务(TimerTask)顾名思义,就是说当定时器到达指定的时间时要做的工作,这里是想Handler发送一个消息,由Handler类进行处理。
2. java.util.Timer.schedule(TimerTask task, long delay):这个方法是说,dalay/1000秒后执行task.只执行一次。
java.util.Timer.schedule(TimerTask task, long delay, long period):这个方法是说,delay/1000秒后执行task,然后进过period/1000秒再次执行task,这个用于循环任务,执行无数次,当然,你可以用timer.cancel();取消计时器的执行。
每一个Timer仅对应唯一一个线程。
Timer不保证任务执行的十分精确。
Timer类的线程安全的。
Timer有以下几种危险
a. Timer是基于绝对时间的。容易受系统时钟的影响。 如果在任务执行期间,更改了系统时间,那么会导致时间计算不准确问题,导致任务没用按找预定的时间执行。
b. Timer只新建了一个线程来执行所有的TimeTask。所有TimeTask可能会相关影响 。 Timer中的任务是依次执行的,并且它对任务的实时调度并没有保证,因为作为底层的实现依赖于Object.wait(long)方法。只能一次执行一个任务,如果前一个任务没有执行完成,后一个任务是无法并行执行的,只能等待前一个任务执行完成才能执行。也有可能会出现这样的结果,前一个任务执行的时间太长,后几个任务时间短,可能在一个时间段内执行了多个任务,任务又没有按照我们要执行的时间执行。
c. Timer不会捕获TimerTask的异常,只是简单地停止。这样势必会影响其他TimeTask的执行。
在Android上呢,可以用 java.util.concurrent.ScheduledThreadPoolExecutor,也可以用Handler机制做,但是不建议使用Timer
ScheduledThreadPoolExecutor采用相对时间,用线程池来执行TimerTask,会出来TimerTask异常。JDK1.5
API中关于这个类的详细介绍:
"可另行安排在给定的延迟后运行命令,或者定期执行命令。需要多个辅助线程时,或者要求 ThreadPoolExecutor 具有额外的灵活性或功能时,此类要优于 Timer。
一旦启用已延迟的任务就执行它,但是有关何时启用,启用后何时执行则没有任何实时保证。按照提交的先进先出 (FIFO) 顺序来启用那些被安排在同一执行时间的任务。 虽然此类继承自 ThreadPoolExecutor,但是几个继承的调整方法对此类并无作用。特别是,因为它作为一个使用 corePoolSize 线程和一个无界队列的固定大小的池,所以调整 maximumPoolSize 没有什么效果。"
我们使用Timer或者handler的时候会发现,delay时间并没有那么准。如果我们需要一个严格准时的定时操作,那么就要用到AlarmManager,AlarmManager对象配合Intent使用,可以定时的开启一个Activity,发送一个BroadCast,或者开启一个Service.
Timer类的还有一个明显的短板:不适用于需要长期在后台运行的定时任务。为了让手机更耐用,每个手机都有自己的休眠策略,Android手机就会在长时间不操作的情况下自动让CPU进入睡眠状态,这可能导致Timer中的定时任务无法正常运行。而Alarm机制则不会出现这种情况,因为它有唤醒CPU的功能,即可以保证每次需要执行定时任务的时候CPU都能正常工作。
长期在后台执行定时任务:
在onStartCommand中开启一个子线程,在里面执行具体操作。然后用getSystemService得到一个AlarmManager,然后用set设置定时任务,启动广播接收器。一小时后,在广播接收器中的onReceive就会执行,然后在里面启动Service,这样就形成了一个循环,LongRunningService会一小时就启动一次。
或者用setRepeating:
在Android开发中,定时执行任务的3种实现方法:
一、采用Handler与线程的sleep(long)方法(不建议使用,java的实现方式)
二、采用Handler的postDelayed(Runnable, long)方法(最简单的android实现)
三、采用Handler与timer及TimerTask结合的方法(比较多的任务时建议使用)
下面逐一介绍:
一、采用Handle与线程的sleep(long)方法
Handler主要用来处理接受到的消息。这只是最主要的方法,当然Handler里还有其他的方法供实现,有兴趣的可以去查API,这里不过多解释。
1. 定义一个Handler类,用于处理接受到的Message。
[java] view
plaincopy
Handler handler = new Handler() {
public void handleMessage(Message msg) {
// 要做的事情
super.handleMessage(msg);
}
};
2. 新建一个实现Runnable接口的线程类,如下:
[java] view
plaincopy
public class MyThread implements Runnable {
@Override
public void run() {
while (true) {
//不断循环,实现每隔10s发送一次Message
try {
Thread.sleep(10000);// 线程暂停10秒,单位毫秒
Message message = new Message();
message.what = 1;
handler.sendMessage(message);// 发送消息
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
3. 在需要启动线程的地方加入下面语句:
[java] view
plaincopy
new Thread(new MyThread()).start();
4. 启动线程后,线程每10s发送一次消息。
二、采用Handler的postDelayed(Runnable, long)方法
这个实现比较简单一些。
1. 定义一个Handler类
[java] view
plaincopy
Handler handler=new Handler();
Runnable runnable=new Runnable() {
@Override
public void run() {
//要做的事情
handler.postDelayed(this, 2000);
}
};
2. 启动计时器
[java] view
plaincopy
handler.postDelayed(runnable, 2000);//每两秒执行一次runnable.
3. 停止计时器
[java] view
plaincopy
handler.removeCallbacks(runnable);
三、采用Handler与timer及TimerTask结合的方法
1. 定义定时器、定时器任务及Handler句柄
[java] view
plaincopy
private final Timer timer = new Timer();
private TimerTask task;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 要做的事情
super.handleMessage(msg);
}
};
2. 初始化计时器任务
[java] view
plaincopy
task = new TimerTask() {
@Override
public void run() {
// TODO Auto-generated method stub
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
}
};
3. 启动定时器
[java] view
plaincopy
timer.schedule(task, 2000, 2000);
3. 停止计时器
[java] view
plaincopy
timer.cancel();
简要说一下上面三步提到的一些内容:
1. 定时器任务(TimerTask)顾名思义,就是说当定时器到达指定的时间时要做的工作,这里是想Handler发送一个消息,由Handler类进行处理。
2. java.util.Timer.schedule(TimerTask task, long delay):这个方法是说,dalay/1000秒后执行task.只执行一次。
java.util.Timer.schedule(TimerTask task, long delay, long period):这个方法是说,delay/1000秒后执行task,然后进过period/1000秒再次执行task,这个用于循环任务,执行无数次,当然,你可以用timer.cancel();取消计时器的执行。
每一个Timer仅对应唯一一个线程。
Timer不保证任务执行的十分精确。
Timer类的线程安全的。
Timer有以下几种危险
a. Timer是基于绝对时间的。容易受系统时钟的影响。 如果在任务执行期间,更改了系统时间,那么会导致时间计算不准确问题,导致任务没用按找预定的时间执行。
b. Timer只新建了一个线程来执行所有的TimeTask。所有TimeTask可能会相关影响 。 Timer中的任务是依次执行的,并且它对任务的实时调度并没有保证,因为作为底层的实现依赖于Object.wait(long)方法。只能一次执行一个任务,如果前一个任务没有执行完成,后一个任务是无法并行执行的,只能等待前一个任务执行完成才能执行。也有可能会出现这样的结果,前一个任务执行的时间太长,后几个任务时间短,可能在一个时间段内执行了多个任务,任务又没有按照我们要执行的时间执行。
c. Timer不会捕获TimerTask的异常,只是简单地停止。这样势必会影响其他TimeTask的执行。
在Android上呢,可以用 java.util.concurrent.ScheduledThreadPoolExecutor,也可以用Handler机制做,但是不建议使用Timer
ScheduledThreadPoolExecutor采用相对时间,用线程池来执行TimerTask,会出来TimerTask异常。JDK1.5
API中关于这个类的详细介绍:
"可另行安排在给定的延迟后运行命令,或者定期执行命令。需要多个辅助线程时,或者要求 ThreadPoolExecutor 具有额外的灵活性或功能时,此类要优于 Timer。
一旦启用已延迟的任务就执行它,但是有关何时启用,启用后何时执行则没有任何实时保证。按照提交的先进先出 (FIFO) 顺序来启用那些被安排在同一执行时间的任务。 虽然此类继承自 ThreadPoolExecutor,但是几个继承的调整方法对此类并无作用。特别是,因为它作为一个使用 corePoolSize 线程和一个无界队列的固定大小的池,所以调整 maximumPoolSize 没有什么效果。"
我们使用Timer或者handler的时候会发现,delay时间并没有那么准。如果我们需要一个严格准时的定时操作,那么就要用到AlarmManager,AlarmManager对象配合Intent使用,可以定时的开启一个Activity,发送一个BroadCast,或者开启一个Service.
Timer类的还有一个明显的短板:不适用于需要长期在后台运行的定时任务。为了让手机更耐用,每个手机都有自己的休眠策略,Android手机就会在长时间不操作的情况下自动让CPU进入睡眠状态,这可能导致Timer中的定时任务无法正常运行。而Alarm机制则不会出现这种情况,因为它有唤醒CPU的功能,即可以保证每次需要执行定时任务的时候CPU都能正常工作。
长期在后台执行定时任务:
<pre name="code" class="javascript">public class LongRunningService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { new Thread(){ <span> </span>@Override <span> </span>public void run() { <span> </span>//执行具体的定时任务 <span> </span>} <span> </span>}; <span> </span>AlarmManager alarmManager= (AlarmManager) getSystemService(ALARM_SERVICE); <span> </span>int anHour=60*60*1000;//一小时 long triggerAtTime= SystemClock.elapsedRealtime()+anHour; Intent i=new Intent(LongRunningService.this,AlarmReceiver.class); PendingIntent pi=PendingIntent.getBroadcast(this,0,i,0); //ELAPSED_REALTIME_WAKEUP:让定时任务的触发时间从系统开机开始算起,并会唤醒CPU alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTime,pi); return super.onStartCommand(intent,flags,startId); } private class AlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Intent i=new Intent(context,LongRunningService.class); context.startService(i); } } }
在onStartCommand中开启一个子线程,在里面执行具体操作。然后用getSystemService得到一个AlarmManager,然后用set设置定时任务,启动广播接收器。一小时后,在广播接收器中的onReceive就会执行,然后在里面启动Service,这样就形成了一个循环,LongRunningService会一小时就启动一次。
或者用setRepeating:
public static void sendUpdateBroadcastRepeat(Context ctx){ Intent intent =new Intent(ctx, UpdateReceiver.class); PendingIntent pendingIntent = PendingIntent.getBroadcast(ctx, 0, intent, 0); //开始时间 long firstime=SystemClock.elapsedRealtime(); AlarmManager am = (AlarmManager) ctx.getSystemService(ALARM_SERVICE); //60秒一个周期,不停的发送广播 am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, firstime, 60*1000, pendingIntent); }
相关文章推荐
- Android 的 Binder 机制概念介绍
- Android之自定义View的封装
- Android Studio 版权信息编辑
- Android ANR分析
- Android官方文档翻译 六 1.4Starting Another Activity
- 006CheckBox复选框的使用
- androidStudio 自定义代码模板
- GitHub Android 常用第三方框架源码地址
- 如何查看Android应用使用的内存
- 如何查看Android应用使用的电量
- 使用adbWireless软件进行Android无线调试
- Android 系统性能优化
- Android服务和如何使用服务
- Mac环境Android 6.0虚拟机启动黑屏解决办法
- Android相机应用
- Android Studio 怎么查看方法注释
- android:clipChildren妙用:底部的radioGroup中间的button突出
- android115 自定义控件
- [转]用android LinearLayout和RelativeLayout实现精确布局
- android动画