WorkManager 如何安排对 REST API 的 GET 请求? [英] How does WorkManager schedule GET requests to REST API?

查看:33
本文介绍了WorkManager 如何安排对 REST API 的 GET 请求?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

我的工人类看起来像这样:

public class MyWorker extends Worker {@非空@覆盖公共 WorkerResult doWork() {lookForNewData();返回 WorkerResult.SUCCESS;}公共无效lookForNewData(){MutableLiveDataliveData = new MutableLiveData<>();liveData.observe(lifeCycleOwner, 结果 -> {notifyOnNewData(结果);})APILayer.getInstance().fetchData(searchParams, liveData)}

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

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

解决方案

  1. 安排每天在后台运行一次的作业

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

Constraints 约束 = new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).建造();PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(MyWorker.class, 1, TimeUnit.DAYS).setConstraints(约束).建造();WorkManager workManager = WorkManager.getInstance();workManager.enqueueUniquePeriodicWork("my_unique_worker", ExistingPeriodicWorkPolicy.KEEP, workRequest);

<块引用>

  1. 任务是从 REST API 获取数据(如果可能,将其发布到 LiveData 对象).

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

@Override公共 WorkerResult doWork() {调用call = APILayer.getInstance().fetchData();响应response = call.execute();如果(响应代码()== 200){MyData 数据 = response.body();//...} 别的 {返回 Result.RETRY;}//...返回结果.成功;}

<块引用>

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

您以同步方式获取 API 数据.同步获取您的本地数据,并执行您需要执行的任何操作来比较它们.

<块引用>

  1. 通知用户有新数据可用.

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

WorkManager.getInstance().getStatusById(compressionWork.getId()).observe(lifecycleOwner, workStatus -> {//对状态做一些事情if (workStatus != null && workStatus.getState().isFinished()) {//...}});

对于我们的示例,还有 getStatusesForUniqueWork(String uniqueWorkName).

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

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

参考第 4 点,周期性工作请求的读取状态的工作方式略有不同.它们只在 ENQUEUEDRUNNING 之间切换,直到 CANCELLED.但永远不会有 SUCCEEDEDFAILED 状态.所以听 isFinished() 可能不是你所期望的.

I've had a look at the codelab for WorkManager plus some examples on here, but everything in code I have seen is either related to doing work locally on the device or work uploading to the server, not downloading data and responding to the data received. In the developer guidelines it even says, "For example, an app might need to download new resources from the network from time to time," so I thought it would be perfect for this task. My question is if WorkManager can handle the following scenario and if not, what is the proper tool for handling it:

  1. Schedule a job that runs once a day in background
  2. The job is to do a data fetch from the REST API (and post it to a LiveData object if possible).
  3. When the data returns, check that it is newer than local data.
  4. Notify the user that new data is available.

My worker class looks something like this:

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)
}

My issue is of course that the LiveData object can't observe because there is no activity or fragment that can be its LifecycleOwner. But even if I used a callback from the API to respond to the data arriving, my worker would already have posted that it was successful and it probably would not proceed with the callback, right? So I kind of know this approach is totally wrong, but I can't see any code for getting data with WorkManager

Please help with a proper solution and some example code or some links, either with WorkManager if it can handle this kind of work or something else if it is more appropriate.

解决方案

  1. Schedule a job that runs once a day in background

You can schedule a PeriodicWorkRequest for that, which should be queued with enqueueUniquePeriodicWork. This makes sure only one PeriodicWorkRequest of a particular name can be active at a time.

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);

  1. The job is to do a data fetch from the REST API (and post it to a LiveData object if possible).

This can by done by sending your request synchronously within doWork() of your worker. I wouldn't use LiveData within your Worker class. We come to that later. The API call would look with Retrofit for example like that:

@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;
}

  1. When the data returns, check that it is newer than local data.

You fetched your API data in a synchronous way. Fetch your local data also synchronously and do whatever you need to do to compare them.

  1. Notify the user that new data is available.

If you schedule a task with WorkManager it is guaranteed to run, even if your app is force-quit or the device is rebooted. So your task might complete while your app is not running. If you want to notify the user in any case you can send a notification. If you want to notify the user within a certain screen you can subscribe on your tasks status. For example like this (taken from the official guide):

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

There's also getStatusesForUniqueWork(String uniqueWorkName) for our example.

The official guide is also explaining how to return data from you Task with which you can call setValue() on your MutableLiveData for example.

I would propose to update your local data within your Worker, subscribe on your workers status and once it succeeds update your UI with the local data (if you are not subscribed on your local data anyways, i.e. with Room and LiveData).

Edit: In reference to point 4, reading status of periodic work requests works a little different. They are only switching between ENQUEUED and RUNNING until CANCELLED. But will never have the state SUCCEEDED or FAILED. So listening for isFinished() might not be what you are expecting.

这篇关于WorkManager 如何安排对 REST API 的 GET 请求?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆