20

即使应用程序关闭,我也需要每天在后台调用一个 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小时后它不会运行。请任何人帮我解决。

4

6 回答 6

40

如果你想确保你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);
于 2018-06-28T12:50:55.607 回答
14

我认为存在三个问题。

enqueue myWork1) 每次访问WorkManager实例时,您都会创建一个新的周期性工作。

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

与 Job Scheduler 类似,您必须在将 Work 添加到 Work Manager 之前检查 Work 是否存在。

示例代码:

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 小时时间时,您如何验证工作没有运行?

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

3)我只是认为PeriodicWorkRequest提供的WorkManager错误。

自上周开始以来,我一直在多台设备上对其进行测试。我在第一次启动应用程序时创建了一个作品,并且三天没有打开它。第一次运行一次,触发第二次同步时运行两次,在这之间,它增加到 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 阶段。我认为您不应该在生产中使用它。

于 2018-05-21T15:55:55.043 回答
2

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

Android Workmanager PeriodicWorkRequest 不是唯一的

于 2018-05-24T03:34:16.387 回答
1

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

WorkManager.enqueueUniquePeriodicWork(String uniqueWorkName, ExistingPeriodicWorkPolicy existingPeriodicWorkPolicy, PeriodicWorkRequest periodWork) 允许您将唯一的 PeriodicWorkRequest 排队

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

于 2018-06-27T15:25:08.490 回答
0

使用 WorkManager 版本1.0.0-alpha04您可以在此处查看发行说明

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

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

于 2018-07-02T12:35:09.587 回答
0

alpha 01 中存在以下问题:

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

使用最新版本的 WorkManager,即 1.0.0-alpha02。查看发行说明以获取更多信息

于 2018-06-03T03:27:53.907 回答