WorkManager 如何安排对 REST API 的 GET 请求?

Posted

技术标签:

【中文标题】WorkManager 如何安排对 REST API 的 GET 请求?【英文标题】:How does WorkManager schedule GET requests to REST API? 【发布时间】:2018-11-18 13:23:35 【问题描述】:

我查看了 WorkManager 的代码实验室以及此处的一些示例,但我所看到的代码中的所有内容要么与在设备上本地工作或工作上传到服务器有关,而不是下载数据和响应收到的数据。在开发人员指南中甚至说,“例如,一个应用程序可能需要不时从网络下载新资源”,所以我认为它非常适合这项任务。我的问题是 WorkManager 是否可以处理以下情况,如果不能,处理它的正确工具是什么:

    安排每天在后台运行一次的作业 工作是从 REST API 获取数据(如果可能,将其发布到 LiveData 对象)。 当数据返回时,检查它是否比本地数据更新。 通知用户有新数据可用。

我的工人阶级看起来像这样:

public class MyWorker extends Worker 

@NonNull
@Override
public WorkerResult doWork() 
    lookForNewData();
    return WorkerResult.SUCCESS;


public void lookForNewData() 
    MutableLiveData<MyObject> liveData = new MutableLiveData<>();

    liveData.observe(lifeCycleOwner, results -> 
        notifyOnNewData(results);
    )

    APILayer.getInstance().fetchData(searchParams, liveData)

我的问题当然是 LiveData 对象无法观察,因为没有可以成为其 LifecycleOwner 的活动或片段。但即使我使用来自 API 的回调来响应到达的数据,我的工作人员也会发布它是成功的并且它可能不会继续回调,对吧?所以我有点知道这种方法是完全错误的,但是我看不到任何使用 WorkManager 获取数据的代码

请提供适当的解决方案和一些示例代码或一些链接,如果 WorkManager 可以处理这种工作,或者如果它更合适,可以使用其他东西。

【问题讨论】:

【参考方案1】:
    安排每天在后台运行一次的作业

您可以为此安排一个PeriodicWorkRequest,它应该与enqueueUniquePeriodicWork 一起排队。这样可以确保一次只能激活一个特定名称的 PeriodicWorkRequest

Constraints constraint = new Constraints.Builder()
     .setRequiredNetworkType(NetworkType.CONNECTED)
     .build();

PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(MyWorker.class, 1, TimeUnit.DAYS)
     .setConstraints(constraint)
     .build();

WorkManager workManager = WorkManager.getInstance();
workManager.enqueueUniquePeriodicWork("my_unique_worker", ExistingPeriodicWorkPolicy.KEEP, workRequest);
    工作是从 REST API 获取数据(如果可能,将其发布到 LiveData 对象)。

这可以通过在您的工作人员的doWork() 内同步发送您的请求来完成。我不会在您的 Worker 类中使用 LiveData。我们稍后再谈。 API 调用看起来像 Retrofit,例如:

@Override
public WorkerResult doWork() 
     Call<MyData> call = APILayer.getInstance().fetchData();
     Response<MyData> response = call.execute();
     if (response.code() == 200) 
          MyData data = response.body();
          // ...
      else 
          return Result.RETRY;
     
     // ...
     return Result.SUCCESS;

    当数据返回时,检查它是否比本地数据更新。

您以同步方式获取 API 数据。同步获取您的本地数据并执行您需要做的任何事情来比较它们。

    通知用户有新数据可用。

如果您使用WorkManager 安排任务,则保证运行,即使您的应用程序被强制退出或设备重新启动。因此,您的任务可能会在您的应用未运行时完成。如果您想在任何情况下通知用户,您可以发送通知。如果您想在某个屏幕内通知用户,您可以订阅您的任务状态。比如像这样(取自official guide):

WorkManager.getInstance().getStatusById(compressionWork.getId())
.observe(lifecycleOwner, workStatus -> 
    // Do something with the status
    if (workStatus != null && workStatus.getState().isFinished()) 
        // ...
    
);

还有 getStatusesForUniqueWork(String uniqueWorkName) 用于我们的示例。

官方指南还解释了如何从您的任务中返回数据,例如您可以在 MutableLiveData 上调用 setValue()

我建议在您的 Worker 中更新您的本地数据,订阅您的工作人员状态,一旦成功,使用本地数据更新您的 UI(如果您没有订阅本地数据,即使用 Room 和 @ 987654336@)。

编辑:参考第 4 点,定期工作请求的读取状态的工作方式略有不同。他们只在ENQUEUEDRUNNING 之间切换,直到CANCELLED。但永远不会有状态SUCCEEDEDFAILED。所以收听isFinished() 可能不是您所期望的。

【讨论】:

谢谢!仅当回调给出响应时才在 doWork() 中返回结果是我所缺少的!欣赏它【参考方案2】:

这是最初的想法。如果我错了,请有人纠正我。

我的工作人员应该已经发布了它是成功的,它可能不会继续回调,对吧?

我们可以使用API​​响应的回调,构造worker的输出数据并使用worker.setOutputData()设置它 然后收听来自 workManager 的LiveData&lt;WorkStatus&gt;。从这个工作状态中,我们可以使用 workStatus.getOutputdata() 获取 outputData。这些数据可以为我们提供我们想要的 API 响应。

我们可以将此响应传递给工作链中的下一个工作人员,以执行更新本地数据库等任务。

【讨论】:

我刚刚实现了这个,它似乎正在工作,我也可以参考这个作为例子:github.com/googlecodelabs/android-workmanager/blob/master/app/…

以上是关于WorkManager 如何安排对 REST API 的 GET 请求?的主要内容,如果未能解决你的问题,请参考以下文章

使用 WorkManager 在特定时间安排工作

WorkManager 是不是需要 BOOT_COMPLETED?

在 Android 12 中使用 WorkManager

Android Jetpack 从使用到源码深耕调度任务组件WorkManager 从实践到原理

Gmail现在支持安排电子邮件,如何使用gmail rest api工作,还是api支持此功能?

保护对 Kafka Connect 的 REST API 的访问