后台执行的定时任务

Android中的定时任务一般有两种实现方式,一种是使用Java API里提供的Timer类,一种是使用Android的Alarm机制。这两种方式在多数情况下都能实现类似的效果,但Timer有一个明显的短板,它并不太适用于那些需要长期在后台运行的定时任务。我们都知道,为了能让电池更加耐用,每种手机都会有自己的休眠策略,Android手机就会在长时间不操作的情况下自动让CPU进入到睡眠状态,这就有可能导致Timer中的定时任务无法正常运行。而Alarm机制则不存在这种情况,它具有唤醒CPU的功能,即可以保证每次需要执行定时任务的时候CPU都能正常工作。需要注意,这里唤醒CPU和唤醒屏幕完全不是同一个概念,千万不要产生混淆。

1.获取一个AlarmManager的实例

AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

2.调用AlarmManager的set()方法就可以设置一个定时任务了,比如说想要设定一个任务在10秒钟后执行

long triggerAtTime = SystemClock.elapsedRealtime() + 10 * 1000;
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pendingIntent);

第一个参数是一个整型参数,用于指定AlarmManager的工作类型,有四种值可选,分别是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()方法可以获取到系统开机至今所经历时间的毫秒数。
使用System.currentTimeMillis()方法可以获取到1970年1月1日0点至今所经历时间的毫秒数。
第二个参数就是定时任务触发的时间,以毫秒为单位。
第三个参数是一个PendingIntent,这里我们一般会调用getBroadcast()方法来获取一个能够执行广播的PendingIntent。这样当定时任务被触发的时候,广播接收器的onReceive()方法就可以得到执行。

后台执行定时任务的代码:

1.服务类

public class LongRunningService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
Log.d("LongRunningService", "executed at " + new Date(). toString());
}
}).start();
AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
int anHour = 60 * 60 * 1000; // 这是一小时的毫秒数
long triggerAtTime = SystemClock.elapsedRealtime() + anHour;
Intent i = new Intent(this, AlarmReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
return super.onStartCommand(intent, flags, startId);
}
}

2.广播类

public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, LongRunningService.class);
context.startService(i);
}
}

onReceive()方法里的代码非常简单,就是构建出了一个Intent对象,然后去启动LongRunningService这个服务。那么这里为什么要这样写呢?其实在不知不觉中,这就已经将一个长期在后台定时运行的服务完成了。因为一旦启动LongRunningService,就会在onStartCommand()方法里设定一个定时任务,这样一小时后AlarmReceiver的onReceive()方法就将得到执行,然后我们在这里再次启动LongRunningService,这样就形成了一个永久的循环,保证LongRunningService可以每隔一小时就会启动一次,一个长期在后台定时运行的服务自然也就完成了。

3.活动类

接下来的任务也很明确了,就是我们需要在打开程序的时候启动一次LongRunningService,之后LongRunningService就可以一直运行了

public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent(this, LongRunningService.class);
startService(intent);
}
}

另外需要注意的是,从Android 4.4版本开始,Alarm任务的触发时间将会变得不准确,有可能会延迟一段时间后任务才能得到执行。这并不是个bug,而是系统在耗电性方面进行的优化。系统会自动检测目前有多少Alarm任务存在,然后将触发时间将近的几个任务放在一起执行,这就可以大幅度地减少CPU被唤醒的次数,从而有效延长电池的使用时间。
当然,如果你要求Alarm任务的执行时间必须准备无误,Android仍然提供了解决方案。使用AlarmManager的setExact()方法来替代set()方法,就可以保证任务准时执行了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值