用于在后台运行日常任务的 Android WorkManager api

Posted

技术标签:

【中文标题】用于在后台运行日常任务的 Android WorkManager api【英文标题】:Android WorkManager api for running daily task in Background 【发布时间】:2018-10-29 03:46:03 【问题描述】:

即使应用程序关闭,我也需要每天在后台调用一个 API。我看过 WorkManager API。对于我的场景,我尝试了 PeriodicWorkRequest 但不幸的是,它没有达到我的预期结果。我所做的是我在 Application 类中使用了这段代码

 PeriodicWorkRequest.Builder myWorkBuilder =
                new PeriodicWorkRequest.Builder(MyWorker.class, 24,
                        TimeUnit.HOURS);

        PeriodicWorkRequest myWork = myWorkBuilder.build();
        WorkManager.getInstance().enqueue(myWork);

但应用程序第一次打开时重复运行11次,24小时后不再运行。请各位大神帮我解决一下。

【问题讨论】:

【参考方案1】:

如果您想确保您的PeriodicWorkRequest 不会被多次创建,您可以使用WorkManager.enqueueUniquePeriodicWork 方法来安排您的工作人员:

此方法允许您将唯一命名的 PeriodicWorkRequest 排入队列,其中一次只能激活一个特定名称的 PeriodicWorkRequest。例如,您可能只希望一个同步操作处于活动状态。如果有一个待处理,您可以选择让它运行或用您的新工作替换它。


例如:

PeriodicWorkRequest.Builder myWorkBuilder =
            new PeriodicWorkRequest.Builder(MyWorker.class, 24, TimeUnit.HOURS);

PeriodicWorkRequest myWork = myWorkBuilder.build();
WorkManager.getInstance()
    .enqueueUniquePeriodicWork("jobTag", ExistingPeriodicWorkPolicy.KEEP, myWork);

【讨论】:

onetimerequest 是否也有类似的选项?有时,相同的工作会被并行调用两次。如何阻止这种情况? @Aram 你试过beginUniqueWork(...)吗? 是的,我试过了,但我们需要使用 Workcontinuation 对象。我不知道那个选项是否更昂贵。有什么想法吗? 根据最佳实践我们应该在应用程序的哪个位置配置作业? 上面的代码 sn-p 在具有 android Pie (9) 的设备 (OnePlus 4T) 中启动 PeriodicWorkRequest,不工作,WorkManager 没有将 Worker 排队。因为我也在这里寻求有关 *** 的帮助:***.com/questions/56697105/…【参考方案2】:

我认为存在三个问题。

1) 每次 enqueue myWorkWorkManager 实例时,您都会创建一个新的周期性工作。

试试看,MyWorker.classdoWork() 方法中的逻辑第一次运行一次,第二次运行两次。您很可能向工作管理器添加了 11 个作品,这就是您上次检查时它运行 11 次的原因。如果您创建新作品并将其添加到工作管理器中,则myWork 运行的次数会增加。

与 Job Scheduler 类似,您必须先检查 Work 是否存在,然后才能将其添加到 Work Manager。

示例代码:

final WorkManager workManager = WorkManager.getInstance();
final LiveData<List<WorkStatus>> statusesByTag = workManager
        .getStatusesByTag(TAG_PERIODIC_WORK_REQUEST);

    statusesByTag.observe(this, workStatuses -> 
    if (workStatuses == null || workStatuses.size() == 0) 
        Log.d(TAG, "Queuing the Periodic Work");
        // Create a periodic request
        final PeriodicWorkRequest periodicWorkRequest =
                new PeriodicWorkRequest.Builder(SyncWorker.class, 30, TimeUnit.MINUTES)
                        .addTag(TAG_PERIODIC_WORK_REQUEST)
                        .build();

        // Queue the work
        workManager.enqueue(periodicWorkRequest);
     else 
        Log.d(TAG, "Work Status Size: " + workStatuses.size());
        for (int i = 0; i < workStatuses.size(); i++) 
            Log.d(TAG, "Work Status Id: " + workStatuses.get(i).getId());
            Log.d(TAG, "Work Status State: " + workStatuses.get(i).getState());
        
        Log.d(TAG, "Periodic Work already exists");
    
);

在上面的示例中,我使用了一个唯一标签 TAG_PERIODIC_WORK_REQUEST 来识别我的周期性工作,并在创建它之前检查它是否存在。

2) 当应用被终止时,您的工作可能没有运行。

您要测试的品牌是什么?是小米吗?您是否在其他多个品牌上进行过测试并得到相同的结果?

是否处于打盹模式?当您设置 24 小时时间时,您如何验证工作没有运行?

工作管理器提供向后兼容性,但您仍然需要处理设备特定的逻辑。在小米设备上,类似于 Job Scheduler(或 Firebase Job Dispatcher 或 Alarm),当应用被杀死时,周期性工作停止。

3) 我只是觉得WorkManager 提供的PeriodicWorkRequest 有问题。

自上周开始以来,我一直在多台设备上对其进行测试。我在第一次启动应用程序时创建了一个作品,并且三天没有打开它。第一次运行一次,触发第二次同步时运行两次,在这之间,它增加到 13 次,下降到 1 次,4 次等等。

在另一个测试中,我在第一次安装期间使用以下代码创建了一个作品,并从第二次安装中删除了该代码。在这个测试过程中,即使工作成功完成,工作每次都运行,杀死后打开应用程序。

final PeriodicWorkRequest periodicWorkRequest =
            new PeriodicWorkRequest.Builder(SyncWorker.class, 30, TimeUnit.MINUTES)
                    .addTag("periodic-work-request")
                    .build();

// Queue the work
WorkManager.getInstance().enqueue(periodicWorkRequest);

我明白,因为它仍处于 alpha 阶段。我认为您不应该在生产中使用它。

【讨论】:

谢谢 Srikar。我使用的是小米设备,为了测试,我设置了 20 分钟。它运行不正确。希望我能再次回到作业调度程序。 在小米上,后台作业仅在将 省电模式 选项设置为 时运行。 不要认为JobScheduler 也会运行。如果有,请告诉我。 @SrikarReddy 小米设备有什么破解方法吗? @AbhishekBatra 除了“自动启动”或“省电模式禁用”之外,你有没有针对红米手机的任何解决方案..【参考方案3】:

如果您在PeriodicWorkRequestBuilder 中添加标签,然后在将定期请求排入队列之前调用WorkManager.getInstance().cancelAllWorkByTag(REQUEST_TAG),这将防止欺骗发生:

Android Workmanager PeriodicWorkRequest is not unique

【讨论】:

【参考方案4】:

alpha03开始,您可以安排一个独特的周期性工作: https://developer.android.com/jetpack/docs/release-notes

WorkManager.enqueueUniquePeriodicWork(String uniqueWorkName, 现有的定期工作政策现有的定期工作政策, PeriodicWorkRequest periodWork) 允许您将唯一的 定期工作请求

所以现在实现你想要的就相当简单了。

【讨论】:

【参考方案5】:

alpha 01 中存在以下问题:

修复了导致工人在 Application.onCreate() 上重新安排的问题。

使用最新版本的 WorkManager,即 1.0.0-alpha02。查看release notes了解更多信息

【讨论】:

我正在使用 1.0.0-alpha02 但仍然有同样的问题。 这里也一样。越来越多的工作创建每个应用程序启动。 看起来问题还没有解决【参考方案6】:

使用 WorkManager 版本 1.0.0-alpha04。您可以查看发行说明here

此外,请参阅此PeriodicWorkRequest GitHub demo,它在维护时段内每天(每 24 小时)更新一次日计数器。它执行 doWork() 方法,无论应用程序是打开还是关闭。

WorkManager 仍处于 alpha 模式,因此一旦发布最终版本,它将完全适用于所有设备。

【讨论】:

以上是关于用于在后台运行日常任务的 Android WorkManager api的主要内容,如果未能解决你的问题,请参考以下文章

android现代化后台任务WorkManager,kotlin

RabbitMQ使用介绍2—Work queues

RabbitMQ指南之二:工作队列(Work Queues)

Android 后台任务执行

在Android中用Kotlin的Anko运行后台任务(KAD 09)

如何清晰地掌握 Android 应用中后台任务的执行情况?