android 定点定时任务,Android定时任务

本章目录

Part One:Timer

Part Two:AlarmManager

Android中有很多种实现定时任务的方式,比如Timer,CountDownTimer, AlarmManager,handler和Thread。不过,主要常用的有三种:

Timer(Java遗留的)

Handler(下雪动画那篇使用过了)

AlarmManager(Android官方推荐)

Part One:Timer

Timer是一个定时器工具,包含一系列的schedule方法用于实施定时计划。TimerTask是一个子线程的抽象类,方便在后台处理一些比较复杂的逻辑,然后利用Handler在主线程刷新UI。

下面我们通过修改先前的案例来认识一下这两个类的具体应用。

首先,在activity_main.xml的cacheContainer_main布局容器中,放一个TextView,用来显示滚动文字。

然后在MainActivity里面初始化这个TextView和SnowView(这里初始化SnowView是用来关闭自定义View的绘制)。

private TextView textView;

private SnowView snowView;

private void initViews() {

cacheContainer = findViewById(R.id.cacheContainer_main);

animContainer = findViewById(R.id.animContainer_main);

leftAnimImageView = findViewById(R.id.leftAnimContainer_main);

rightAnimImageView = findViewById(R.id.rightAnimContainer_main);

textView = findViewById(R.id.textView_main);

snowView = findViewById(R.id.snowView_main);

}

接着初始化一段文字数组,用来以滚动的方式,不断更新显示的文字。

private String[] contents = new String[]{"时间久了,我都快忘记我们相识多少年了,",

"我只知道我认识你很久了,", "漫长的时间却拉不近我们的距离,",

"一天一点爱恋,一夜一点思念,", "不想再等了,有些话想对你说。"};

最后,把先前定义的openWindow方法改成switchContent,让方法名字表达的更准确一些。同时在方法里初始化Timer和TimerTask,并调用相应的方法。

private int index = 0;//数组的索引,用于让TextView显示不同内容,初识从0开始

private void switchContent() {

final Timer timer = new Timer();

timer.schedule(new TimerTask() {

@Override

public void run() {

//刷新UI必须执行在主线程

runOnUiThread(new Runnable() {

@Override

public void run() {

//如果字符串数组全部显示完毕,下标清0,防止越界。同是,让自定义View停止绘制。

//Timer停止计划任务,并执行开窗动画

if (index == contents.length){

index = 0;

snowView.stopDraw();

initCache();

timer.cancel();

}

//让TextView滚动显示文字

textView.setText(contents[index]);

index++;

}

});

}

}, 50, 4000);

}

整个计划任务的实现逻辑并不复杂,就是不断变换数组索引坐标,让TextView显示不同的内容。

这里要重点说一下我们使用的timer.schedule(task, delay, period)的三个参数:

task:TimerTask对象,就是要周期执行的任务。

delay:从计时器初始化完毕后,开始启动的延迟时间。

period:定时器的间隔时间。

比如,我们的案例就是50毫秒后启动定时器,没4秒更新一下文字,文字刷新完执行动画。

滚动文字.gif

Part Two:AlarmManager

前面提到的Timer实现定时任务的方式使用的是Java的API,大部分情况下都是满足需求的,比如本例。但是如果遇到手机锁屏或者关机,唤醒CPU执行定时任务时,就会遇到一些问题,比如闹钟。所以,官方推荐使用AlrmManager来执行定时任务。

AlarmManager的实现方式也不是很复杂,只是需要用到PendingIntent,具体步骤如下:

先前的准备工作不变,只是改变switchContent方法。首先,注释掉先前写的代码,然后声明一个全局的AlarmManager

private void switchContent() {

alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);

}

private AlarmManager alarmManager;

然后声明一个全局的PendingIntent,并设置AlarmManager的重复方式

private void switchContent() {

alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);

Intent intent = new Intent();

intent.setAction("action.REFRESHTEXTVIEW");

pendingIntent = PendingIntent.getBroadcast(this,

100, intent, PendingIntent.FLAG_CANCEL_CURRENT);

alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,

5000, 60000, pendingIntent);

}

private AlarmManager alarmManager;

private PendingIntent pendingIntent;

其中,PendingIntent是个延迟意图对象,这里是发送广播,所以使用getBroadcast方法,也可以使用getService启动Service或者getActivity启动Activity来执行某项固定任务。getBroadcast的参数前面都好理解,最后一个参数的效果有:

FLAG_CANCEL_CURRENT:如果系统中有一个相同的PendingIntent对象,那么就取消旧的,然后重新生成一个。

FLAG_NO_CREATE:如果当前系统中不存在相同的PendingIntent对象,系统将不会创建该PendingIntent对象而是直接返回null。

FLAG_ONE_SHOT:该PendingIntent只作用一次。在该PendingIntent对象通过send()方法触发过后,PendingIntent将自动调用cancel()进行销毁,那么如果你再调用send()方法的话,系统将会返回一个SendIntentException。

FLAG_UPDATE_CURRENT:如果系统中有一个和你描述的PendingIntent对等的PendingInent,那么系统将使用该PendingIntent对象,但是会使用新的Intent来更新之前PendingIntent中的Intent对象数据,例如更新Intent中的Extras。

另外,setRepeating也需要注意,从Android5.0开始,第二个参数triggerAtMillis(触发时间)不得低于5秒,intervalMillis(重复间隔)不得低于60秒。这两个参数如果比这两个值小,默认分别是5秒和60秒,只有大于才会生效,因为间隔太短会费电~短时间的定时任务,官方推荐使用Handler方式。

所以,其实AlarmManager并不适合本例,这里只是讲一下用法。

setRepeating方法的第一个参数也单独说下:

AlarmManager.RTC_WAKEUP表示闹钟在睡眠状态下会唤醒系统并执行提示功能,该状态下闹钟使用绝对时间,状态值为0;

AlarmManager.RTC表示闹钟在睡眠状态下不可用,该状态下闹钟使用绝对时间,即当前系统时间,状态值为1;

AlarmManager.ELAPSED_REALTIME_WAKEUP表示闹钟在睡眠状态下会唤醒系统并执行提示功能,该状态下闹钟也使用相对时间,状态值为2;

AlarmManager.ELAPSED_REALTIME表示闹钟在手机睡眠状态下不可用,该状态下闹钟使用相对时间(相对于系统启动开始),状态值为3;

AlarmManager.POWER_OFF_WAKEUP表示闹钟在手机关机状态下也能正常进行提示功能,所以是5个状态中用的最多的状态之一,该状态下闹钟也是用绝对时间,状态值为4;不过本状态好像受SDK版本影响,某些版本并不支持;

接下来就是自定义一个广播接收者,当接收到广播时,执行的任务:

private class AlarmBroadcastReceiver extends BroadcastReceiver {

@Override

public void onReceive(Context context, Intent intent) {

if (index == contents.length) {

index = 0;

snowView.stopDraw();

initCache();

alarmManager.cancel(pendingIntent);//取消定时器

}

//让TextView滚动显示文字

textView.setText(contents[index]);

index++;

}

}

最后,将广播注册即可

IntentFilter intentFilter = new IntentFilter();

intentFilter.addAction("action.REFRESHTEXTVIEW");

BroadcastReceiver receiver = new AlarmBroadcastReceiver();

registerReceiver(receiver, intentFilter);

结果就是每隔60秒发送一个广播,广播接收器收到广播后,执行相应的任务。

你可能感兴趣的:(android,定点定时任务)