检查是不是已经安排了 WorkManager
Posted
技术标签:
【中文标题】检查是不是已经安排了 WorkManager【英文标题】:Check if WorkManager is scheduled already检查是否已经安排了 WorkManager 【发布时间】:2019-01-07 18:50:05 【问题描述】:我如何检查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);
我在Application
班级的onCreate()
中致电scheduleWork()
。
甚至我也可以通过 this method 检查我的服务是否正在运行。但如果 WorkManager 已经安排在预定时间消除不一致,我不想安排它。
喜欢
if(!workManagerIsScheduled())
scheduleWork();
有什么解决办法吗?
【问题讨论】:
您可以获取工作请求的状态...进行检查 你试过了吗? 查看答案@Man 没有必要检查 worker 是否已经在运行,因为您正在使用带有 'ExistingPeriodicWorkPolicy.KEEP' 的 instance.enqueueUniquePeriodicWork()。仅当没有标记为 uniqueWorkName 的待处理工作时,它才会运行新的 PeriodicWorkRequest。 'ExistingPeriodicWorkPolicy.KEEP' 用于特定任务,而不是用于工作。如果某个服务正在完成它的工作,那么这个标志会保持服务运行直到它完成它的工作。 【参考方案1】:更新
如果您只是因为不想重复工作而需要检查已经运行的工作管理器。你可以简单地使用enqueueUniquePeriodicWork()
此方法允许您将唯一命名的 PeriodicWorkRequest,其中只有一个 PeriodicWorkRequest 的 特定名称可以同时处于活动状态。例如,您只能 希望一个同步操作处于活动状态。如果有一个待处理,您可以 选择让它运行或用你的新作品替换它。
因此您无需担心作品的重复性。
workmanager.enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.KEEP , photoCheckWork);
TAG 是唯一名称,工作经理将通过该名称检查重复性。
你可以choose betweenExistingPeriodicWorkPolicy.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;
当它的某些任务是 RUNNING
或 ENQUEUED
时,它将返回 true
。
示例代码
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);
【讨论】:
你好 Khemraj 你的解决方案给了我这种类型的错误 androidx.work.impl.utils.futures.SettableFuture cannot be cast to android.arch.lifecycle.LiveData It can't be cast LiveData> statuses = instance.getStatusesByTag(tag); 如果您希望获取实时数据状态,则必须根据新 API 将“getStatusesByTag(tag)”更改为“getStatusesByTagLiveData(tag)”。State.BLOCKED
呢?为什么它不用于检查? developer.android.com/topic/libraries/architecture/workmanager/…。它解释了一个任务正在等待其他任务完成,它应该按顺序运行。理想情况下,我们不应该使用!state.isFinished()
来检查任何仍在排队、正在运行或等待运行的任务。
检查 instance.getWorkInfosByTag(tag) 时总是返回空列表,所以我使用 instance.getWorkInfosForUniqueWork(tag) 在依赖项中工作正常 -> 实现“androidx.work:work-runtime:2.2.0”
你应该使用running |= state == WorkInfo.State.RUNNING | state == WorkInfo.State.ENQUEUED;
否则,running
将具有最后一个workInfo
的值【参考方案2】:
从 1.0.0-alpha11 以及许多 WorkStatus 将不起作用,它已被删除,这是一个重大变化。 Check Release Notes
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】:自 2018 年 10 月 11 日起,您可以使用 ListenableFuture 代替已删除的 SynchronousWorkManager:
您现在可以使用 ListenableFutures 同步获取和观察。例如,WorkManager.enqueue() 用于返回 void;它现在返回一个 ListenableFuture。操作完成后,您可以调用 ListenableFuture.addListener(Runnable, Executor) 或 ListenableFuture.get() 运行代码。
更多信息可以在here找到。
另一个选项可以使用 ListenableWorker:
一个可以在 WorkManager 中异步执行工作的类。在大多数情况下,我们建议使用 Worker,它提供了一个在预先指定的后台线程上执行的简单同步 API。
调用 startWork() 函数后返回 ListenableFuture。
更多信息可以在here找到。
【讨论】:
我似乎无法在我的项目中解析SynchronousWorkManager
...它被删除了吗?
是的,它似乎从 10 月 11 日起就消失了。您可以改用 ListenableFuture。
由于已删除 SynchronousWorkManager,此答案已过时,您可能会考虑将其删除。
@Ridcully 删除了过时的信息并添加了有关 ListenableWorker 的更多信息。【参考方案4】:
接受的答案是错误的(很糟糕,因为它会默默地失败)。 这是一个正确的答案
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。
【讨论】:
【参考方案5】:我在这篇文章中找到了答案,并进行了一些编辑。
在我的项目中;我每 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");
【讨论】:
【参考方案6】:我认为我们应该通过 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
【讨论】:
以上是关于检查是不是已经安排了 WorkManager的主要内容,如果未能解决你的问题,请参考以下文章