Check if WorkManager is scheduled already

无人久伴 提交于 2019-11-29 02:25:47

Update

If you need to check already running work manager just because you don't want duplicate works. You can simply use enqueueUniquePeriodicWork()

This method allows you to enqueue a uniquely-named PeriodicWorkRequest, where only one PeriodicWorkRequest of a particular name can be active at a time. For example, you may only want one sync operation to be active. If there is one pending, you can choose to let it run or replace it with your new work.

So you don't need to worry about duplicacy about works.

 workmanager.enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.KEEP , photoCheckWork);
  • Where TAG is unique name by which work manager will check duplicacy.
  • You can choose between ExistingPeriodicWorkPolicy.KEEP and ExistingPeriodicWorkPolicy.REPLACE.

Orignal Post

I created this method when I did not find any.

Check if work is running by 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;
}

It will return true when some of its task is RUNNING or ENQUEUED.

Sample code

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

from 1.0.0-alpha11 along with many things WorkStatus will not work it's removed and it's a breaking change. Check Release Notes

WorkStatus has been renamed to WorkInfo. All corresponding getStatus method variants have been renamed to the corresponding getWorkInfo variants. This is a breaking change.

after updating to alpha11 the working code is.

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

Problem with the answer which uses LiveData solution is that value can be null even if the job is scheduled and you should use Observer to check the status. To avoid this you can use SynchronousWorkManager.

public static boolean isWorkScheduled(String tag) {
    SynchronousWorkManager instance = WorkManager.getInstance().synchronous();
    List<WorkStatus> statuses = instance.getStatusesByTagSync(tag);
    if (statuses.isEmpty()) return false;
    boolean running = false;
    for (WorkStatus workStatus : statuses) {
        running = workStatus.getState() == State.RUNNING
                | workStatus.getState() == State.ENQUEUED;
    }
    return running;
}

Of course the problem with this solution is that it cannot be run on a main Thread since it accesses the dabatase. But this solution is pretty good if you have multiple Workers but only one can run at the same time or if for some reason one Worker needs to schedule another one, which is my case.

EDIT: Seems like SynchronousWorkManager was removed on October 11:

Removed WorkManager.synchronous() and WorkContinuation.synchronous() and all related methods. Added ListenableFuture as the return type of many methods in the API. This is a breaking API change.

How to use it:

You can now synchronously get and observe by using ListenableFutures. For example, WorkManager.enqueue() used to return void; it now returns a ListenableFuture. You can call ListenableFuture.addListener(Runnable, Executor) or ListenableFuture.get() to run code once the operation is complete.

More info can be found here.

If you are using Kotlin you can write an extension function like this

fun WorkManager.isAnyWorkScheduled(tag: String): Boolean {
    return try {
        getWorkInfosByTag(tag).get().firstOrNull { !it.state.isFinished } != null
    } catch (e: Exception) {
        when (e) {
            is ExecutionException, is InterruptedException -> {
                e.printStackTrace()
            }
            else -> throw e
        }
        false
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!