一、WorkManager
最大优点:
1、执行可靠性保证:系统重启、或应用被干掉,都能恢复任务 (任务状态持久化存储)
2、系统友好性:自动适应系统资源状态、遵循电池优化策略、不会因系统限制而崩溃
其它优点:
3、灵活的任务约束
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED) // 需要网络连接
.setRequiresBatteryNotLow(true) // 电量充足
.setRequiresCharging(true) // 充电时执行
.setRequiresDeviceIdle(true) // 设备空闲时
.setRequiresStorageNotLow(true) // 存储空间充足
.build();
4、任务链支持
WorkManager.getInstance(context)
.beginWith(Arrays.asList(workA, workB)) // 并行执行 A 和 B
.then(workC) // 然后执行 C
.then(workD) // 最后执行 D
.enqueue();
5、可以观察任务状态
WorkManager.getInstance(context)
.getWorkInfoByIdLiveData(workRequest.getId())
.observe(lifecycleOwner, workInfo -> {
if (workInfo != null) {
WorkInfo.State state = workInfo.getState();
// 处理不同状态
switch (state) {
case SUCCEEDED:
// 任务成功
break;
case FAILED:
// 任务失败
break;
case RUNNING:
// 任务运行中
break;
}
}
});
6、支持任务输入输出数据
缺点:
因系统友好性,所以在某些场景下,不能精确执行
- 在系统休眠时,任务会被延迟执行
- 系统唤醒后,延迟的任务会被执行
使用建议:
- 对于需要保证执行的后台任务,优先使用 WorkManager
- 合理设置任务约束,避免过度消耗系统资源
- 利用任务链功能组织复杂的任务流程
- 注意观察任务状态,及时处理异常情况
- 对于需要精确定时的任务,可以考虑配合 AlarmManager 使用
二、AlarmManger
最大优点:
1、比较强势,保证精确执行:
- 由系统服务直接管理
- 可以在应用被干掉后继续工作
- 即使设备休眠也会准时触发
- 在低功耗模式下也能保证执行
- 可以唤醒设备执行任务
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// 精确定时,即使设备休眠也会准时触发
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
triggerTime,
pendingIntent
);
}
2、多种触发模式
// 精确时间触发,会唤醒设备
alarmManager.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
// 精确时间触发,不唤醒设备
alarmManager.setExact(AlarmManager.RTC, time, pendingIntent);
// 相对时间触发,从设备启动时开始计时
alarmManager.setExact(AlarmManager.ELAPSED_REALTIME, time, pendingIntent);
// 允许不精确触发,系统可能会将多个闹钟合并
alarmManager.set(AlarmManager.RTC, time, pendingIntent);
3、重复任务支持
// 设置重复闹钟
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
firstTime,
intervalMillis,
pendingIntent
);
实现方式
使用AlarmManager简单实现定时每天或重复执行任务,有3种方式
1)AlarmManager+Service 实现方式
2)AlarmManager+InterService 实现方式
3)AlarmManger + BoardcastReceiver 实现方式
需要在AndroidMainifast.xml 增加权限
1)增加ALARM(闹钟)权限
<uses-permission android:name="android.permission.SET_ALARM"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2)增加Service和BoardcastReceiver注册
<service android:name=".service.AlarmService" /> <service android:name=".service.AlarmIntentService"/> <receiver android:name=".broadcast.AlarmBroadcastReceiver" />
3)Service和BoardcastReceiver定义
3.1)AlarmService
public class AlarmService extends Service {
private final String TAG = "AlarmService";
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 在这里执行你的任务
Log.e(TAG,"调用闹钟,调用时间:"+ DateHelper.timestampToDate(System.currentTimeMillis()) );
// 任务执行完毕后,停止Service
stopSelf();
return START_NOT_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
3.2)AlarmIntentService
public class AlarmIntentService extends IntentService
{
private final String TAG = "AlarmIntentService";
public AlarmIntentService()
{
super("AlarmIntentService");
}
@Override
protected void onHandleIntent(Intent intent)
{
Log.e(TAG,"调用闹钟,调用时间:"+ DateHelper.timestampToDate(System.currentTimeMillis()) );
}
}
3.3)AlarmBoardcastReceiver
public class AlarmBroadcastReceiver extends BroadcastReceiver
{
private final String TAG = "AlarmBroadcastReceiver";
public static String alarmboradcastAction = "alarm.broadcast.upload";
@Override
public void onReceive(Context context, Intent intent)
{
if(intent.getAction().equals(alarmboradcastAction))
{
Log.e(TAG,"调用闹钟,调用时间:"+ DateHelper.timestampToDate(System.currentTimeMillis()));
}
}
}
4)AlarmManager结合Service、IntentService、boardcastReceiver使用
4.1)AlarmManager+Service 使用
/**
* AlarmManager + Service 实现定时任务
* */
public void AlarmServiceTest(){
// 设置定时任务的代码片段
Intent alarmIntent = new Intent(this, AlarmService.class);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, alarmIntent, 0);
AlarmManager alarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
// 设置单次闹钟或重复闹钟
// 设置为单次闹钟
long triggerAtMillis = System.currentTimeMillis() + 1000; // 10秒后触发
alarmManager.set(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent);
// 或者设置重复闹钟(最小时间间隔:1 min)
//long intervalMillis = 1000 * 60*1; // 每隔60秒触发一次
//alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), intervalMillis, pendingIntent);
}
4.2)AlarmManager+IntentService 使用
/**
* AlarmManager + IntentService 实现定时任务
* */
public void AlarmInterServiceTest(){
// 设置定时任务的代码片段
Intent alarmIntent = new Intent(this, AlarmIntentService.class);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, alarmIntent, 0);
AlarmManager alarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
// 设置单次闹钟或重复闹钟
// 设置为单次闹钟
//long triggerAtMillis = System.currentTimeMillis() + 1000; // 10秒后触发
//alarmManager.set(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent);
// 或者设置重复闹钟(最小时间间隔:1 min)
long intervalMillis = 1000 * 60*1; // 每隔60秒触发一次
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), intervalMillis, pendingIntent);
}
4.3)AlarmManager+BroadcastReceiver 使用
/**
* AlarmManager+BroadcastReceiver 方式实现定时任务
* */
public void AlarmBroadcastTest(){
// 设置定时任务的代码片段
Intent alarmIntent = new Intent(this, AlarmBroadcastReceiver.class);
alarmIntent.setAction(AlarmBroadcastReceiver.alarmboradcastAction);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
AlarmManager alarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
// 设置单次闹钟或重复闹钟
// 设置为单次闹钟
//long triggerAtMillis = System.currentTimeMillis() + 1000; // 10秒后触发
//alarmManager.set(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent);
// 或者设置重复闹钟
long intervalMillis = 1000 * 60*1; // 每隔60秒触发一次1000 * 60
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), intervalMillis, pendingIntent);
}
AlarmManager 重置延迟时间:
public void resetAlarmDelay(Context context, long newDelayMillis) {
// 取消现有的闹钟
if (alarmManager != null && pendingIntent != null) {
alarmManager.cancel(pendingIntent);
}
// 获取 AlarmManager 服务
alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// 创建 PendingIntent
Intent intent = new Intent(context, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
);
// 设置新的延迟时间
long triggerTime = System.currentTimeMillis() + newDelayMillis;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Android 6.0 及以上使用 setExactAndAllowWhileIdle
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
triggerTime,
pendingIntent
);
} else {
// 低版本使用 setExact
alarmManager.setExact(
AlarmManager.RTC_WAKEUP,
triggerTime,
pendingIntent
);
}
}
注意事项:
1. 重置时会先取消旧的闹钟
2. 使用 FLAG_UPDATE_CURRENT 更新现有的 PendingIntent
3. 根据系统版本使用不同的设置方法
4. 记得在适当时机取消闹钟
三、其它定时处理
Handler :
- UI 相关的延时任务
- 需要在主线程执行的任务
- 简单的定时器功能
- 不能保证精确执行,且不保证执行可靠性,应用层面的
Timer:
不适合安卓系统