Android 程序的定时任务主要有AlarmManager、WorkManager两种。 一、AlarmManager AlarmManager,又称闹钟,可以设置一次性任务,周期重复任务,定时重复任务。 AlarmManager 通过
Android 程序的定时任务主要有AlarmManager、WorkManager两种。
AlarmManager,又称闹钟,可以设置一次性任务,周期重复任务,定时重复任务。
AlarmManager 通过 PendingIntent 传递要执行的任务程序,可以是广播、跳转页面、后台服务、前台服务等。
本节参考文章:https://zhuanlan.zhihu.com/p/544564416
PendingIntent 是一种延迟的 Intent,表示一种延迟执行的意图操作。
PendingIntent 一种是支持授权其他应用以当前应用的身份执行包装的 Intent 操作的系统特性。
从结构上来说,PendingIntent 是 Intent 的包装类
使用代码示例:
Intent intent = new Intent(this, MyIntentService.class); PendingIntent serviceIntent = PendingIntent.getService(this, requestCode, intent,PendingIntent.FLAG_UPDATE_CURRENT| PendingIntentPendingIntent.FLAG_IMMUTABLE);
简单说明下创建 PendingIntent 的 4 个参数:
context: 当前应用的上下文,PendingIntent 将从中抽取授权信息;
2、requestCode: PendingIntent 的请求码,与 Intent 的请求码类似;
3、intent: 最终的意图操作;
4、flag: 控制标记位。
创建 PendingIntent 时有一个容易犯错的地方需要注意:重复调用 PendingIntent.getActivity() 等创建方法不一定会返回新的对象,系统会基于两个要素判断是否需要返回相同的对象
闹钟执行方法设置
1)一次性执行
alarmMgr.set(@AlarmType int type, long triggerAtMillis, PendingIntent operation)
2)重复执行
setRepeating()和setInexactRepeating()都可以设置重复任务,官方推荐使用setInexactRepeating()
alarmMgr.setInexactRepeating(@AlarmType int type, long triggerAtMillis, long intervalMillis, PendingIntent operation)
type,闹钟类型
triggerAtMillis,首次触发时间,毫秒数
intervalMillis,每次执行时间间隔,毫秒数
闹钟类型说明:
一次性任务,1分钟后执行
private AlarmManager alarmMgr;private PendingIntent alarmIntent;...alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);Intent intent = new Intent(context, AlarmReceiver.class);alarmIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT| PendingIntent.FLAG_IMMUTABLE);alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 60 * 1000, alarmIntent);
重复任务,30分钟后执行,每间隔30分钟执行1次,注意:最短间隔时间是1分钟
private AlarmManager alarmMgr;private PendingIntent alarmIntent;...alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);Intent intent = new Intent(context, MyIntentService.class);alarmIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT| PendingIntent.FLAG_IMMUTABLE);alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR, AlarmManager.INTERVAL_HALF_HOUR, alarmIntent);
在下午 2:00 左右唤醒设备并触发闹钟,并在每天的同一时间重复一次
// 设置闹钟在下午2:00执行Calendar calendar = Calendar.getInstance();calendar.setTimeInMillis(System.currentTimeMillis());calendar.set(Calendar.HOUR_OF_DAY, 14);// 设置每隔一天执行一次alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, alarmIntent);
在上午 8:30 准时唤醒设备并触发闹钟,此后每 20 分钟触发一次
private AlarmManager alarmMgr;private PendingIntent alarmIntent;...alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);Intent intent = new Intent(context, AlarmReceiver.class);alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);// 设置闹钟在上午8:30 执行Calendar calendar = Calendar.getInstance();calendar.setTimeInMillis(System.currentTimeMillis());calendar.set(Calendar.HOUR_OF_DAY, 8);calendar.set(Calendar.MINUTE, 30);// 设置闹钟每隔20分钟触发一次alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 1000 * 60 * 20, alarmIntent);
使用PendingIntent.FLAG_NO_CREATE
获取已存在的PendingIntent
,然后执行cancel()
方法
Intent intent = new Intent(this, MyIntentService.class);AlarmManager alarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_IMMUTABLE);if (pendingIntent != null && alarmManager != null) { Log.i("cancelAlarm", "cancelAlarm: " + pendingIntent); pendingIntent.cancel(); alarmManager.cancel(pendingIntent);} else { Log.i("cancelAlarm", "not found Alarm !");}
1)添加设备权限
2)实现 BroadcastReceiver 以接收广播,判断设备启动事件
public class SampleBootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) { // 判断设备启动事件 } }}
3)配置 Intent 过滤器过滤器,添加android.intent.action.BOOT_COMPLETED
本节参考官方文档:https://developer.android.google.cn/topic/libraries/architecture/workmanager/basics
WorkManager 是适合用于持久性工作的推荐解决方案。如果工作始终要通过应用重启和系统重新启动来调度,便是持久性的工作。由于大多数后台处理操作都是通过持久性工作完成的,因此 WorkManager 是适用于后台处理操作的主要推荐 api。
WorkManager 适用于需要可靠运行的工作,即使用户导航离开屏幕、退出应用或重启设备也不影响工作的执行。例如:
WorkManager 不适用于那些可在应用进程结束时安全终止的进程内后台工作。它也并非对所有需要立即执行的工作都适用的通用解决方案。
WorkManager 的使用简单描述3个步骤
将以下依赖项添加到应用的build.gradle
文件中
dependencies { def work_version = "2.7.1" // (Java only) implementation "androidx.work:work-runtime:$work_version" // Kotlin + coroutines implementation "androidx.work:work-runtime-ktx:$work_version" // optional - RxJava2 support implementation "androidx.work:work-rxjava2:$work_version" // optional - GCMNetworkManager support implementation "androidx.work:work-gcm:$work_version" // optional - Test helpers androidTestImplementation "androidx.work:work-testing:$work_version" // optional - Multiprocess support implementation "androidx.work:work-multiprocess:$work_version"}
工作使用 Worker 类定义。doWork() 方法在 WorkManager 提供的后台线程上异步运行。
如需为 WorkManager 创建一些要运行的工作,请扩展 Worker 类并替换 doWork() 方法。例如,如需创建上传图像的 Worker,您可以执行以下操作:
public class UploadWorker extends Worker { public UploadWorker( @NonNull Context context, @NonNull WorkerParameters params) { super(context, params); } @Override public Result doWork() { // 获取传入的参数 String name = getInputData().getString("name"); Log.i("Worker", "uploadImages: name: "+ name); uploadImages(); return Result.success(); } private void uploadImages() { Log.i("Worker", "uploadImages: test2"); }}
从 doWork() 返回的 Result 会通知 WorkManager 服务工作是否成功,以及工作失败时是否应重试工作。
定义工作后,必须使用 WorkManager 服务进行调度该工作才能运行。对于如何调度工作,WorkManager 提供了很大的灵活性。您可以将其安排为在某段时间内定期运行,也可以将其安排为仅运行一次。
不论您选择以何种方式调度工作,请始终使用 WorkRequest。Worker 定义工作单元,WorkRequest(及其子类)则定义工作运行方式和时间。
1)OneTimeWorkRequest 示例
WorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(UploadWorker.class) .build();
2)PeriodicWorkRequest 示例
PeriodicWorkRequest 最短执行周期是15分钟,如果设置的循环周期小于15分钟也会被设置为15分钟
最好给WorkRequest设置Tag值,以便在启动时,删除旧的执行任务,防止重复执行
PeriodicWorkRequest uploadWorkRequest = new PeriodicWorkRequest.Builder(UploadWorker.class, 15, TimeUnit.MINUTES) // Constraints .setInitialDelay(10, TimeUnit.SECONDS) .addTag("task") .setInputData(new Data.Builder() .putString("name","Hello") .build()) .build();
最后,您需要使用 enqueue() 方法将 WorkRequest 提交到 WorkManager。
WorkManager .getInstance(this) .enqueue(uploadWorkRequest);
如果要要取消任务可使用方法
// 取消所有任务WorkManager.getInstance(this).cancelAllWork();// 取消指定任务WorkManager.getInstance(this).cancelAllWorkByTag("task");
执行加急工作
您可以控制当应用达到其执行配额时加急工作会发生什么情况。如需继续,您可以传递 setExpedited():
OneTimeWorkRequest request = new OneTimeWorkRequestBuilder() .setInputData(inputData) .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) .build();
工作约束
约束可确保将工作延迟到满足最佳条件时运行
Constraints constraints = new Constraints.Builder() .setRequiredNetworkType(NetworkType.UNMETERED) .setRequiresCharging(true) .build();WorkRequest myWorkRequest = new OneTimeWorkRequest.Builder(MyWork.class) .setConstraints(constraints) .build();
重试和退避政策
如果您需要让 WorkManager 重试工作,可以从工作器返回 Result.retry()。然后,系统将根据退避延迟时间和退避政策重新调度工作。
每个工作请求都有退避政策和退避延迟时间。默认政策是 EXPONENTIAL,延迟时间为 10 秒,但您可以在工作请求配置中替换此设置。
WorkRequest myWorkRequest = new OneTimeWorkRequest.Builder(MyWork.class) .setBackoffCriteria( BackoffPolicy.LINEAR, OneTimeWorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS) .build();
链接工作,执行多个工作
您可以使用 WorkManager 创建工作链并将其加入队列。工作链用于指定多个依存任务并定义这些任务的运行顺序。
如需创建工作链,您可以使用 WorkManager.beginWith(OneTimeWorkRequest) 或 WorkManager.beginWith(List),这会返回 WorkContinuation 实例
WorkManager.getInstance(myContext) // Candidates to run in parallel .beginWith(Arrays.asList(plantName1, plantName2, plantName3)) // Dependent work (only runs after all previous work in chain) .then(cache) .then(upload) // Call enqueue to kick things off .enqueue();
--结束END--
本文标题: Android开发之定时任务(AlarmManager、WorkManager)
本文链接: https://www.lsjlt.com/news/373629.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
下载Word文档到电脑,方便收藏和打印~
2024-05-16
2024-05-16
2024-05-16
2024-05-16
2024-05-16
2024-05-16
2024-05-16
2024-05-16
2024-05-16
2024-05-16
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0