Android下的定时任务

Android中的定时任务一般有两种实现方式,一种是使用JavaAPI里的Timer类,另一种是使用android的Alarm机制。

这两种方式在多数情况下都能实现类似的效果,但Timer有一个明显的短板,它并不太适用与那些需要长期在后台运行的定时任务。As we know,为了能让电池更加耐用,每种手机都会有自己的休眠策略:比如手机不用的时候智能的断开wifi连接,根据光纤强弱自动调节屏幕亮度,根据手机长时间无操作时自动的让CPU进入到休眠状态等,当进入休眠状态时,这就有可能导致Timer中的定时任务无法正常运行。而Alarn机制则不存在这种情况,它具有唤醒CPU的功能,即可以保证每次需要执行定时任务的时候CPU都能正常工作。需要注意的是,这里的唤醒CPU和唤醒屏幕不是同一个概念,不能混淆。



Timer类

使用Timer及TimerTask可以在某个时间执行某一个任务。

Timer是一个普通的类,有几个重要的方法。而TimerTask是一个抽象类,要使用的时候必须实现它的Run方法。

TimerTask的run方法类似于线程的run方法。 我们使用Timer创建一个他的对象,然后使用这对象的schedule方法来完成这种间隔的操作。

schedule方法有三个参数

第一个参数就是TimerTask类型的对象,我们实现TimerTask的run()方法就是要周期执行的一个任务;

第二个参数有两种类型,第一种是long类型,表示多长时间后开始执行,另一种是Date类型,表示从那个时间后开始执行;

第三个参数就是执行的周期,为long类型。

schedule方法还有一种两个参数的执行重载,第一个参数仍然是TimerTask,第二个表示为long的形式表示多长时间后执行一次,为Date就表示某个时间后执行一次。

Timer就是一个线程,使用schedule方法完成对TimerTask的调度,多个TimerTask可以共用一个Timer,也就是说Timer对象调用一次schedule方法就是创建了一个线程,并且调用一次schedule后TimerTask是无限制的循环下去的,使用Timer的cancel()停止操作。当然同一个Timer执行一次cancel()方法后,所有Timer线程都被终止。

 1 //true 说明这个timer以daemon方式运行(优先级低,程序结束timer也自动结束)
 2 java.util.Timer timer = new java.util.Timer(true);
 3 TimerTask task = new TimerTask() {
 4     public void run() {
 5         //每次需要执行的代码放到这里面。
 6     }
 7 };
 8
 9
10 //以下是几种调度task的方法:
11
12 //time为Date类型:在指定时间执行一次。
13 timer.schedule(task, time);
14
15 //firstTime为Date类型,period为long,表示从firstTime时刻开始,每隔period毫秒执行一次。
16 timer.schedule(task, firstTime, period);
17
18 //delay 为long类型:从现在起过delay毫秒执行一次。
19 timer.schedule(task, delay);
20
21 //delay为long,period为long:从现在起过delay毫秒以后,每隔period毫秒执行一次。
22 timer.schedule(task, delay, period);


Alarm机制

1.首先获取到AlarmManager的实例。
AlarmManager manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE)
然后调用AlarmManager的set()方法就可以设置一个定时任务了。

long triggerAtTime = SystemClock.elapsedRealtime() + 10 * 100;

manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtime,pendingIntent);

set()方法中第一个参数是一个整型参数,用于指定AlarmManager的工作类型,有4种值可选,分别是ELAPSED_REALTIME、ELAPSED_REALTIME_WAKEUP、RTC和RTC_WAKEUP。

ELAPSED_REALTIME:表示让定时任务的触发时间从系统开机开始算起,但不会唤醒CPU。

ELAPSED_REALTIME_WAKEUP:同样表示让定时任务的触发时间从系统开机时间开始算起,但会唤醒CPU。

RTC:表示让定时任务的触发时间从1970年1月1日0点开始算起,但不会唤醒CPU。

RTC_WAKEUP:表示让定时任务的触发时间从1970年1月1日0点开始算起,但会唤醒CPU。

使用SystemClock.elapsedRealtime()方法可以获取到系统开机至今所经历时间的毫秒数。

使用SystemClock.currentTimeMills()方法可以获取到1970年1月1日0点至今所经历时间的毫秒数。

第二个参数是定时任务的触发时间,以毫秒为单位。

若第一个参数使用的是ELAPSED_REALTIME或是ELAPSED_REALTIME_WAKEUP那么这里传入开机至今的时间再加上延迟执行的时间。

若第一个参数使用的是RTC或是RTC_WAKEUP,那么这里传入1970年1月1日0点至今的时间再加上延迟执行的时间。

第三个参数是PendingIntent。

pendingIntent是一种特殊的Intent。主要的区别在于Intent的执行立刻的,而pendingIntent的执行不是立刻的。pendingIntent执行的操作实质上是参数传进来的Intent的操作,但是使用pendingIntent的目的在于它所包含的Intent的操作的执行是需要满足某些条件的。主要的使用的地方和例子:通知Notificatio的发送,短消息SmsManager的发送和警报器AlarmManager的执行等等。

PendingIntent中

getActivity(Context, int, Intent, int) 跳转到一个activity组件
getBroadcast(Context, int, Intent, int) 发送一个广播组件
getService(Context, int, Intent, int) 启动一个服务组件

这里我们一般会调用getService()方法或者getBroadcast()方法来获取一个能够执行服务或者广播的PendingIntent。这样当定时任务被触发的时候。服务的onStartCommand()方法或者广播的onReceive()方法就可以得到执行。

如果想要实现一个长时间在后台定时运行的服务该怎么做呢?

只需要定义一个服务,并将触发定时任务的代码写到onStartCommand()方法中。

 1 @Override
 2     public int onStartCommand(Intent intent,int flags, int startId) {
 3         new Thread(new Runnable() {
 4             @Override
 5             public void run() {
 6                 //在这里执行具体逻辑
 7             }
 8         }).start();
 9         AlarmManager manager = (AlarmManager)getSystemService(ALARM_SERVICE);
10         int anHour = 60 * 60 * 1000; //这是一小时的毫秒数。
11         long triggerAtTimer = SystemClock.elapsedRealtime() + anHour;
12         Intent i = new Intent(this,LongRunningService.class);
13         PendingIntent pi = PendingIntent.getService(this,0,i,0);
14         manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTimer,pi);
15         return super.onStartCommand(intent,flags,startId);
16     }

我们首先是在onStartCommand()方法中开启了一个子线程,这样就可以在这里执行具体的逻辑操作了,之所以要在子线程里执行逻辑操作,是因为逻辑操作也是需要耗时的,如果放在主线程里执行可能会对

定时任务的准确性造成轻微的影响。

创建线程代码之后,先是获取到了AlarmManager的实例, 然后定义任务的触发时间为一个小时后,再使用PendingIntent指定处理定时任务的服务为LongRunningService,最后调用set()方法完成设定。

一旦启动LongRunningService,就会在onStartCommand()方法里设定了一个定时任务,这样一个小时后,将会再次启动LongRunningService。从而形成一个永久的循环,保证LongRunningService的onStartCommand()方法可以每隔一个小时就执行一次。

如果想要启动定时服务的时候调用以下代码即可。

 Intent intent = new Intent(context,LongRunningService.class);
    context.startService(intent);

需要注意的是,从Android4.4开始,Alarm任务的触发时间将会变得不准确,有可能会延迟一段时间后任务才能执行,这是系统在耗电性方面的优化,系统会自动检测目前有多少Alarm任务存在,然后将触发时间相近的几个任务放在一起执行,这样就可以大幅度减少CPU被唤醒的次数,从而减少耗电量。

如果要求Alarm任务的执行时间必须准确无误,只需要使用AlarmManager的setExact()方法来替代set()方法。就基本上可以保证任务能够准时执行了。

 

时间: 2024-10-29 19:12:20

Android下的定时任务的相关文章

Android下将图片载入到内存中

Android的系统的标准默认每一个应用程序分配的内存是16M.所以来说是很宝贵的,在创建应用的时候要尽可能的去节省内存,可是在载入一些大的文件的时候,比方图片是相当耗内存的,一个1.3M的图片,分辨率是2560X1920(宽X高)图片当载入到手机内存的时候就会请求19M的一块内存,这是远远超出了系统自带的内存空间,这时候应用程序就会挂掉,所以我们要进行图片的缩放处理,以下我就来带大家创建一个用来图片缩放的应用: 应用效果图例如以下: 核心代码的实现: package com.examp.loa

fiddler Android下https抓包全攻略

fiddler Android下https抓包全攻略 fiddler的http.https的抓包功能非常强大,可非常便捷得对包进行断点跟踪和回放,但是普通的配置对于像招商银行.支付宝.陌陌这样的APP是抓不到包的,需要一些特殊的配置,本文把fiddler Android下https抓包的详细配置都罗列出来,供大家参考. 一.普通https抓包设置 先对Fiddler进行设置: 勾选“CaptureHTTPS CONNECTs”,接着勾选“Decrypt HTTPS traffic”.同时,由于我

Android下pm 命令详解

Sam在看相关PackageManager代码时,无意中发现Android 下提供一个pm命令,通常放在/system/bin/下.这个命令与Package有关,且非常实用.所以研究之.0. Usage: usage: pm [list|path|install|uninstall] pm list packages [-f] pm list permission-groups pm list permissions [-g] [-f] [-d] [-u] [GROUP] pm list ins

android下的单元测试

android下的单元测试 在AndroidManifest.xml文件中配置以下信息: 在manifest节点下添加: <!-- 指定测试信息和要测试的包 --> <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.jxn.junittest" /> 在application节点下添加: <!

cocos搭建android下的开发环境

没想到cocos3.2也出现了一点bug,还要经过一周晚上的努力,全部搞定.可以在android下使用啦 上个截图庆祝下 有需要的可以看http://item.taobao.com/item.htm?id=40745006457 cocos搭建android下的开发环境,布布扣,bubuko.com

Android下EditText的hint的一种显示效果------FloatLabelLayout

效果: 此为EditText的一种细节,平时可能用的不多,但是用户体验蛮好的,特别是当注册页面的项目很多的时候,加上这种效果,体验更好 仅以此记录,仅供学习参考. 参考地址:https://gist.github.com/chrisbanes/11247418 采用的是Android 3.0的动画,所以有版本限制,可以用  nineoldandroids  做向下兼容 ,当然上面的网址也给了另一种方式做向下兼容. demo地址:http://download.csdn.net/detail/ab

sae Python下设置定时任务

官方文档在这里:http://sae.sina.com.cn/doc/python/cron.html 就是通过在config.yaml文件中添加Cron段,例如: cron: - description: timing_task url: /on_time schedule: "*/5 * * * *" 代表每5分钟以get方式访问/on_time这个链接. 还可以结合sae中的Taskqueue服务把大任务分成小任务,因为sae对于每次访问有时间限制,不能超过300秒. 提醒:冒号

Android下的动画

        ------你需要努力,你还没资格休息----- Android下的动画有三种: tween补间动画.frame帧动画.property属性动画(Android3.0后提出来的). 补间动画: Translation(平移).Rotation(旋转).Alpha(透明).Scale(缩放) 代码方式:透明动画AlphaAnimation alpha=new AlphaAnimation(0,1); alpha.setDuration(2000);//执行的时间 alpha.set

Android 下拉刷新上拉加载 多种应用场景 超级大放送(上)

转载请标明原文地址:http://blog.csdn.net/yalinfendou/article/details/47707017 关于Android下拉刷新上拉加载,网上的Demo太多太多了,这里不是介绍怎么去实现下拉刷新上拉加载,而是针对下拉刷新上拉加载常用的一些应用场景就行了一些总结,包含了下拉刷新上拉加载过程中遇到的一些手势冲突问题的解决方法(只能算是抛砖引玉). 去年9月的时候,那时自己正在独立做Android项目.记得刚刚写完那个ListView列表页面(木有下拉刷新,上拉加载)