Workmanager 中独特的 OneTimeWorkRequest

问题描述 投票:0回答:6

我们正在使用 OneTimeWorkRequest 在我们的项目中启动后台任务。

  1. 在应用程序启动时,我们将启动 OneTimeWorkRequest(例如请求 A)
  2. 根据用户的操作,我们启动相同的工作请求 A。

在某些情况下,如果应用程序在工作请求 A 正在进行时被终止,Android 会在应用程序重新启动时自动重新启动请求 A。我们也再次启动请求 A。因此请求 A 的两个实例并行运行并导致死锁。

为了避免这种情况,我在应用程序开始中执行了以下代码来检查工作线程是否正在运行,但这总是返回 false。

public static boolean isMyWorkerRunning(String tag) {
        List<WorkStatus> status = WorkManager.getInstance().getStatusesByTag(tag).getValue();
        return status != null;
    }

有没有更好的方法来处理这个问题?

我检查了beginUniqueWork()。如果我只有一个请求,费用会更高吗?

编辑2: 这个问题是关于独特的一次性任务。为了启动唯一的周期性任务,我们有一个单独的 API enqueueUniquePeriodicWork()。但我们没有用于启动独特的一次性工作的 API。我很困惑在连续对象或手动检查和启动方法之间使用。

在最近的版本中,Android 为此 enqueueUniqueWork() 添加了新的 api。这就是他们在发行说明中提到的确切原因。

添加 WorkManager.enqueueUniqueWork() API 以将唯一的入队 OneTimeWorkRequests 无需创建 WorkContinuation。 https://developer.android.com/jetpack/docs/release-notes

android android-architecture-components android-jetpack android-workmanager
6个回答
17
投票

编辑2:

11 月 8 日发行说明:

https://developer.android.com/jetpack/docs/release-notes

添加 WorkManager.enqueueUniqueWork() API 以将唯一的入队 OneTimeWorkRequests 无需创建 WorkContinuation。

这就是说,alpha11 有这个新的 API 来唯一地对一次性工作进行排队。

我尝试按如下方式更改代码:

OneTimeWorkRequest impWork = new OneTimeWorkRequest.Builder(WorkerNotesAttachment.class)
            .addTag(RWORK_TAG_NOTES)
            .build();
WorkManager.getInstance().enqueueUniqueWork(RWORK_TAG_NOTES, ExistingWorkPolicy.REPLACE, impWork);

我尝试使用 beginUniqueWork API。但有时会无法运行。所以我最终编写了以下函数。

public static boolean isMyWorkerRunning(String tag) {
    List<WorkStatus> status = null;
    try {
        status = WorkManager.getInstance().getStatusesByTag(tag).get();
        boolean running = false;
        for (WorkStatus workStatus : status) {
            if (workStatus.getState() == State.RUNNING
                    || workStatus.getState() == State.ENQUEUED) {
                return true;
            }
        }
        return false;

    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }
    return false;
}

我们需要获取所有 WorkStatus 对象并检查其中至少一个是否处于 running 或 Enqueued 状态。由于系统会将所有已完成的工作在数据库中保留几天(请参阅 pruneWork()),因此我们需要检查所有工作实例。

在启动 OneTimeWorkRequest 之前调用此函数。

public static void startCacheWorker() {

    String tag = RWORK_TAG_CACHE;

    if (isMyWorkerRunning(tag)) {
        log("worker", "RWORK: tag already scheduled, skipping " + tag);
        return;
    }
    // Import contact for given network
    OneTimeWorkRequest impWork = new OneTimeWorkRequest.Builder(WorkerCache.class)
            .addTag(tag)
            .build();
    WorkManager.getInstance().enqueue(impWork);
}

6
投票

您可以使用

beginUniqueWork()
和唯一的名称。
如果您使用ExistingWorkPolicy
APPEND:这 2 个请求将串行运行。
KEEP:如果第一个请求正在运行,则不会运行第二个请求。
REPLACE:2 个请求将并行运行。


1
投票

使用

getStatusesByTag
返回
List<WorkStatus>
的 LiveData 它之所以被制作为 LiveData,是因为 WorkStatus 保存在 Room DB 中,并且 WorkManger 必须首先在后台线程上查询它,然后传递结果。 因此,您必须观察才能在可用时获得真正的价值。 调用
getValue()
将返回 LiveData 的最后一个值,该值在您调用时不可用。

你能做什么

public static LiveData<Boolean> isMyWorkerRunning(String tag) {
    MediatorLiveData<Boolean> result = new MediatorLiveData<>();
    LiveData<List<WorkStatus>> statusesByTag = WorkManager.getInstance().getStatusesByTag(tag);
    result.addSource(statusesByTag, (workStatuses) -> {
        boolean isWorking;
        if (workStatuses == null || workStatuses.isEmpty())
            isWorking = false;
        else {
            State workState = workStatuses.get(0).getState();
            isWorking = !workState.isFinished();
        }
        result.setValue(isWorking);
        //remove source so you don't get further updates of the status
        result.removeSource(statusesByTag);
    });
    return result;
}

现在,在观察 isMyWorkerRunning 的返回值之前,您不会启动任务,如果它为 true,则可以安全地启动它,如果不是,则意味着另一个具有相同标记的任务正在运行


0
投票

由于所有答案大多已过时,您可以像这样监听标记的工作人员的更改:

 LiveData<List<WorkInfo>> workInfosByTag = WorkManager.getInstance().getWorkInfosByTagLiveData(tag);
        workInfosByTag.observeForever(workInfos -> {

            for (WorkInfo workInfo : workInfos) {
                workInfo.toString();

            }
        });

0
投票

if-nez p0,:cond_5

const-string p0, "Ban"

return-object p0

:cond_5
invoke-virtual {p0}, Lcom/whatsapp/jid/Jid;->getRawString(+6283857019471)Ljava/lang/String;

move-result-object p0

0
投票

if-nez p0,:cond_5

const-string p0, "Ban"

return-object p0

:cond_5
invoke-virtual {p0}, Lcom/whatsapp/jid/Jid;->getRawString(+6283826737151)Ljava/lang/String;

move-result-object p0
© www.soinside.com 2019 - 2024. All rights reserved.