检查 WorkManager 是否已被安排

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

如何检查

WorkManager
是否已安排。

这是我安排的代码

WorkManager

public static void scheduleWork() {
    PeriodicWorkRequest.Builder photoCheckBuilder =
            new PeriodicWorkRequest.Builder(WorkManagerService.class, TIME_INTERVAL_IN_SECONDS,
                    TimeUnit.SECONDS);
    PeriodicWorkRequest photoCheckWork = photoCheckBuilder.build();
    WorkManager instance = WorkManager.getInstance();
    if (instance != null) {
        instance.enqueueUniquePeriodicWork("TAG", ExistingPeriodicWorkPolicy.KEEP , photoCheckWork);
    }
}

我在我的

scheduleWork()
班级的
onCreate()
中打电话给
Application
。 即使我也可以通过这个方法检查我的服务是否正在运行。但如果已经安排了 WorkManager,我不想安排它以消除安排时间的不一致。

喜欢

if(!workManagerIsScheduled())
   {
     scheduleWork();
   }

有什么解决办法吗?

android android-workmanager
8个回答
118
投票

更新

如果您只是因为不想重复工作而需要检查已经运行的工作管理器。您可以简单地使用 enqueueUniquePeriodicWork()

此方法允许您将唯一命名的 periodicworkrequest,其中只有一个periodicworkrequest 特定名称可以同时处于活动状态。例如,您可能只 想要激活一项同步操作。如果有待处理的,您可以 选择让它运行或用您的新作品替换它。

所以您无需担心作品重复。

 workmanager.enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.KEEP , photoCheckWork);
  • 其中 TAG 是唯一名称,工作经理将通过该名称检查重复性。
  • 您可以
    ExistingPeriodicWorkPolicy.KEEP
    ExistingPeriodicWorkPolicy.REPLACE
    之间进行选择。

原帖

当我没有找到任何方法时,我创建了这个方法。

检查工作是否正在按TAG运行

if (your_work_manager.version >= 1.0.0-alpha11)

private boolean isWorkScheduled(String tag) {
    WorkManager instance = WorkManager.getInstance();
    ListenableFuture<List<WorkInfo>> statuses = instance.getWorkInfosByTag(tag);
    try {
        boolean running = false;
        List<WorkInfo> workInfoList = statuses.get();
        for (WorkInfo workInfo : workInfoList) {
            WorkInfo.State state = workInfo.getState();
            running = state == WorkInfo.State.RUNNING | state == WorkInfo.State.ENQUEUED;
        }
        return running;
    } catch (ExecutionException e) {
        e.printStackTrace();
        return false;
    } catch (InterruptedException e) {
        e.printStackTrace();
        return false;
    }
}

if (your_work_manager.version < 1.0.0-alpha11)

private boolean isWorkScheduled(String tag) {
    WorkManager instance = WorkManager.getInstance();
    LiveData<List<WorkStatus>> statuses = instance.getStatusesByTag(tag);
    if (statuses.getValue() == null) return false;
    boolean running = false;
    for (WorkStatus workStatus : statuses.getValue()) {
        running = workStatus.getState() == State.RUNNING | workStatus.getState() == State.ENQUEUED;
    }
    return running;
}

当某些任务是

true
RUNNING
时,它将返回
ENQUEUED

示例代码

public static final String TAG_MY_WORK = "mywork";

if(!isWorkScheduled(TAG_MY_WORK)) { // check if your work is not already scheduled
    scheduleWork(TAG_MY_WORK); // schedule your work
}

public static void scheduleWork(String tag) {
    PeriodicWorkRequest.Builder photoCheckBuilder =
            new PeriodicWorkRequest.Builder(WorkManagerService.class, TIME_INTERVAL_IN_SECONDS,
                    TimeUnit.SECONDS);
    PeriodicWorkRequest photoCheckWork = photoCheckBuilder.build();
    WorkManager instance = WorkManager.getInstance();
    instance.enqueueUniquePeriodicWork(tag, ExistingPeriodicWorkPolicy.KEEP , photoCheckWork);
}

9
投票

接受的答案是错误的(很糟糕,因为它默默地失败了)。 这是正确答案

private boolean isWorkScheduled(String tag, Context context) {

        WorkManager instance = WorkManager.getInstance(context);
        ListenableFuture<List<WorkInfo>> statuses = instance.getWorkInfosByTag(tag);

        boolean running = false;
        List<WorkInfo> workInfoList = Collections.emptyList(); // Singleton, no performance penalty

        try {
            workInfoList = statuses.get();
        } catch (ExecutionException e) {
            Log.d(TAG, "ExecutionException in isWorkScheduled: " + e);
        } catch (InterruptedException e) {
            Log.d(TAG, "InterruptedException in isWorkScheduled: " + e);
        }

        for (WorkInfo workInfo : workInfoList) {
            WorkInfo.State state = workInfo.getState();
            running = running || (state == WorkInfo.State.RUNNING | state == WorkInfo.State.ENQUEUED);
        }
        return running;

除了进行一些重构以避免误导多次返回之外,错误就在这一行

running = state == WorkInfo.State.RUNNING | state == WorkInfo.State.ENQUEUED;

如果你使用这条线,你只会得到最后评估的

running
。有评论建议使用运算符
=|
来代替。即使结果是正确的,代码也会不清楚并且(稍微)次优。
|
是位运算符,
||
是逻辑运算符。我们要执行的操作是逻辑操作,而不是按位操作。对于布尔值,
|
||
给出相同的结果,但只有
||
是快捷方式,这是我们案例中的预期行为。

此代码至少适用于 WorkManager 2.5.0 和 2.6.0。


6
投票

1.0.0-alpha11 以及许多东西 WorkStatus 将无法工作,它已被删除,这是一个重大更改。 检查发行说明

WorkStatus 已重命名为 WorkInfo。所有相应的 getStatus 方法变体已重命名为相应的 getWorkInfo 变体。这是一个重大改变。

更新到 alpha11 后,工作代码是。

private boolean isWorkScheduled(List<WorkInfo> workInfos) {

    boolean running = false;

    if (workInfos == null || workInfos.size() == 0) return false;

    for (WorkInfo workStatus : workInfos) {
        running = workStatus.getState() == WorkInfo.State.RUNNING | workStatus.getState() == WorkInfo.State.ENQUEUED;
    }

    return running;
}

3
投票

自 10 月 11 日(2018 年)起,您可以使用 ListenableFuture 代替已删除的 SynchronousWorkManager

您现在可以使用 ListenableFutures 同步获取和观察。例如,WorkManager.enqueue()用于返回void;它现在返回一个 ListenableFuture。操作完成后,您可以调用 ListenableFuture.addListener(Runnable, Executor) 或 ListenableFuture.get() 来运行代码。

更多信息可以在这里找到。

另一个选项可以使用 ListenableWorker:

WorkManager 中可以异步执行工作的类。对于大多数情况,我们建议使用 Worker,它提供了一个简单的同步 API,在预先指定的后台线程上执行。

调用 startWork() 函数后,它会返回 ListenableFuture

更多信息可以在这里找到。


2
投票

我在这篇文章中找到了答案,并做了一些编辑。

在我的项目中;我每 15 分钟向服务器发送一次位置信息。如果已经安排了 WorkManager,我不想安排它。

// Fırst I'm creating workRequest here.
   private void createWorkRequest() {
        Constraints constraints = new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build();
        PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder
                (LocationWorker.class, 15, TimeUnit.MINUTES)
                .setConstraints(constraints)
                .build();
        WorkManager.getInstance(this)
                .enqueueUniquePeriodicWork("sendLocation", ExistingPeriodicWorkPolicy.REPLACE, periodicWorkRequest);
    }

// Then i'm learning the state of Work
    private WorkInfo.State getStateOfWork() {
        try {
            if (WorkManager.getInstance(this).getWorkInfosForUniqueWork("sendLocation").get().size() > 0) {
                return WorkManager.getInstance(this).getWorkInfosForUniqueWork("sendLocation")
                        .get().get(0).getState();
                // this can return WorkInfo.State.ENQUEUED or WorkInfo.State.RUNNING
                // you can check all of them in WorkInfo class.
            } else {
                return WorkInfo.State.CANCELLED;
            }
        } catch (ExecutionException e) {
            e.printStackTrace();
            return WorkInfo.State.CANCELLED;
        } catch (InterruptedException e) {
            e.printStackTrace();
            return WorkInfo.State.CANCELLED;
        }
    }

// If work not ( ENQUEUED and RUNNING ) i'm running the work.
// You can check with other ways. It's up to you.
    private void startServerWork() {
        if (getStateOfWork() != WorkInfo.State.ENQUEUED && getStateOfWork() != WorkInfo.State.RUNNING) {
            createWorkRequest();
            Log.wtf("startLocationUpdates", ": server started");
        } else {
            Log.wtf("startLocationUpdates", ": server already working");
        }
    }

1
投票

我认为我们应该通过 UniqueWorkName 检查 WorkRequest 的所有六种状态。如果工作请求属于任何州,我们应该将其标记为已安排。您还可以删除案例中的一些状态以满足您的业务需求。

private fun isWorkEverScheduledBefore(context: Context, tag: String): Boolean {
    val instance = WorkManager.getInstance(context)
    val statuses: ListenableFuture<List<WorkInfo>> = instance.getWorkInfosForUniqueWork(tag)
    var workScheduled = false
    statuses.get()?.let {
        for (workStatus in it) {
            workScheduled = (
                        workStatus.state == WorkInfo.State.ENQUEUED
                                || workStatus.state == WorkInfo.State.RUNNING
                                || workStatus.state == WorkInfo.State.BLOCKED
                                || workStatus.state.isFinished // It checks SUCCEEDED, FAILED, CANCELLED already
                    )
        }
    }
    return workScheduled
}

0
投票

如果工作经理已安排

private val _workManagerObserver = WorkManager.getInstance(application)
    .getWorkInfosForUniqueWorkLiveData(TAG)
    .map { it.lastOrNull() }
    .map { it?.state?.isFinished != true }
    .map {
        Timber.d("_workManagerObserver $it")
        it
    }
    .asFlow()

如果工作管理器正在运行

private val _workManagerObserver = WorkManager.getInstance(application)
    .getWorkInfosForUniqueWorkLiveData(TAG)
    .map { it.lastOrNull() }
    .map { it?.state == WorkInfo.State.RUNNING }
    .map {
        Timber.d("_workManagerObserver $it")
        it
    }
    .asFlow()

0
投票

这应该做:

public class MyWorker extends Worker {

    public static boolean isExecuted;

    public MyWorker(Context context, WorkerParameters workerParams) {
        super(context, workerParams);
        isExecuted = true;
    }

    @NonNull
    @Override
    public Result doWork() {
        // ...
    }

}

然后你可以在某个地方调用它来检查之前是否已经安排了工作:

if (!MyWorker.isExecuted) {
WorkRequest workRequest = new OneTimeWorkRequest.Builder(MyWorker.class).build();
WorkManager.getInstance().enqueue(workRequest);
}
© www.soinside.com 2019 - 2024. All rights reserved.