如何观察 Android WorkManager Workers

Hec*_*tor 5 android android-workmanager

我当前的 Android 应用程序采用

archWorkerRuntimeVersion = '2.3.0-beta02'

api "androidx.work:work-runtime:$archWorkerRuntimeVersion"
api "androidx.work:work-runtime-ktx:$archWorkerRuntimeVersion"
Run Code Online (Sandbox Code Playgroud)

处理后台工作。

当工作人员运行时,我会显示一个工具栏进度旋转器,向用户发出该应用程序“忙”的信号。

我的应用程序由多个活动组成,我使用 Android JetPack ViewModels 来管理 Worker。

我开始工作如下:-

val myWorkRequest: OneTimeWorkRequest =
    OneTimeWorkRequest.Builder(MyWorker::class.java)
        .addTag(WORK_IN_PROGRESS_TAG + "${UUID.randomUUID()}").build()

    WorkManager.getInstance(applicationContext)
        .beginUniqueWork(
            UNIQUE_WORK_NAME,
            ExistingWorkPolicy.KEEP,
            myWorkRequest
        )
        .enqueue()
Run Code Online (Sandbox Code Playgroud)

我有一个观察者定义如下:-

private val observer = Observer<WorkInfo> { workInfo ->

    when(workInfo.state) {
        WorkInfo.State.RUNNING -> Log.e("OBSERVING", "${UUID.randomUUID()} :: show Progress Spinner")
        WorkInfo.State.ENQUEUED -> Log.e("OBSERVING", "${UUID.randomUUID()} :: show Progress Spinner")
        WorkInfo.State.SUCCEEDED -> Log.e("OBSERVING", "${UUID.randomUUID()} :: stop showing Progress Spinner")
        WorkInfo.State.FAILED -> Log.e("OBSERVING", "${UUID.randomUUID()} :: stop showing Progress Spinner")
        WorkInfo.State.BLOCKED -> Log.e("OBSERVING", "${UUID.randomUUID()} :: show Progress Spinner")
        WorkInfo.State.CANCELLED -> Log.e("OBSERVING", "${UUID.randomUUID()} :: stop showing Progress Spinner")
    }

}
Run Code Online (Sandbox Code Playgroud)

我对这项工作的观察如下:-

 WorkManager.getInstance(applicationContext)
            .getWorkInfoByIdLiveData(myWorkRequest.id)
            .observe(lifeCycleOwner, observer)
Run Code Online (Sandbox Code Playgroud)

并记住我的视图模型中当前的 workId

class MyViewModel : ViewModel() {

    private var currentWorkInfoId: UUID? = null


  fun startWorkTags(lifeCycleOwner: LifecycleOwner, applicationContext: Context) {

        val myWorkRequest: OneTimeWorkRequest =
    OneTimeWorkRequest.Builder(MyWorker::class.java)
        .addTag(WORK_IN_PROGRESS_TAG + "${UUID.randomUUID()}").build()

    WorkManager.getInstance(applicationContext)
        .beginUniqueWork(
            UNIQUE_WORK_NAME,
            ExistingWorkPolicy.KEEP,
            myWorkRequest
        )
        .enqueue()

        currentWorkInfoId = myWorkRequest.id
   }
}
Run Code Online (Sandbox Code Playgroud)

我有以下问题

1)。当我使用时ExistingWorkPolicy.KEEP,我需要知道何时已经有后台工作处于活动状态,这样我就不会记住错误的工作 ID。目前我无条件记住我上次尝试的工作 ID enqueue()。有什么方法可以检测到何时ExistingWorkPolicy.KEEP导致没有新工作开始?

2)。由于当用户退出我的应用程序时,我将当前工作 ID 存储在我的 viewModel 中,因此我丢失了该 ID。当我的用户重新进入我的应用程序时,如何发现我是否有活跃的工作人员?

对于问题 2)。我尝试过使用

 WorkManager.getInstance(applicationContext)
            .getWorkInfosForUniqueWorkLiveData(UNIQUE_WORK_NAME)
            .observe(lifeCycleOwner, observerUnique)
Run Code Online (Sandbox Code Playgroud)

然而,这种方法“看到”所有以前的工作程序执行,我如何识别最新的工作程序实例?

pfm*_*ggi 2

鉴于您只想在 Worker 运行时显示进度旋转器,您可以实现一种更简单的解决方案,其中您的观察者只需检查是否有一个 Worker 处于非最终状态

observe(this, listOfWorkInfo -> {
    // If there are no matching work info, do nothing
    if (listOfWorkInfo == null || listOfWorkInfo.isEmpty()) {
        return;
    }

    boolean showProgress = false;
    for (WorkInfo workInfo : listOfWorkInfo) {
        if (!(workInfo.getState().isFinished())) {
            showProgress = true;
        }
    }

    if (showProgress) {
        showSpinner();
    } else {
        hideSpinner();
    }

}
Run Code Online (Sandbox Code Playgroud)

您可以在其中获取 WorkInfos 列表getWorkInfosForUniqueWorkLiveData()

另一种解决方案是使用您已经在使用的WorkManager v2.3.0 中引入的新 Progress API 。

这个想法是,一旦你的工作线程启动(在构造函数中),你就发布进度:

import android.content.Context;
import androidx.annotation.NonNull;
import androidx.work.Data;
import androidx.work.Worker;
import androidx.work.WorkerParameters;

public class ProgressWorker extends Worker {

    private static final String PROGRESS = "PROGRESS";
    private static final long DELAY = 1000L;

    public ProgressWorker(
        @NonNull Context context,
        @NonNull WorkerParameters parameters) {
        super(context, parameters);
        // Set initial progress to 0
        setProgressAsync(new Data.Builder().putInt(PROGRESS, 1).build());
    }

    @NonNull
    @Override
    public Result doWork() {
        try {
            // Doing work.
            Thread.sleep(DELAY);
        } catch (InterruptedException exception) {
            // ... handle exception
        }
        return Result.success();
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以使用已有的观察者来检索进度workInfo.getProgress()。这种情况下的好处来自这样一个事实:只有在工作线程运行时,进度信息才可用。
您仍然可以从 UniqueWorkName 请求所有 WorkInfo,但只有在工作线程正在运行时才会有进度。

当工作线程处于最终状态时,WorkManager 将负责删除进度信息。