如何检查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
。
甚至我都可以通过 this method 检查服务是否正在运行。但是我不希望安排WorkManager,前提是已经安排了WorkManager来消除计划的时间上的不一致。
像
if(!workManagerIsScheduled())
{
scheduleWork();
}
有解决方案吗?
答案 0 :(得分:31)
如果您只是因为不想重复工作而需要检查已经在运行的工作管理器。您可以简单地使用enqueueUniquePeriodicWork()
此方法可让您排队一个唯一名称的 PeriodicWorkRequest,其中只有一个 特定名称可以一次处于活动状态。例如,您只能 希望激活一个同步操作。如果有一个未决,您可以 选择运行它还是将其替换为您的新作品。
因此您无需担心作品的重复性。
workmanager.enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.KEEP , photoCheckWork);
ExistingPeriodicWorkPolicy.KEEP
和ExistingPeriodicWorkPolicy.REPLACE
。我找不到任何方法时创建了此方法。
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);
}
答案 1 :(得分:2)
使用LiveData解决方案的答案存在的问题是,即使计划了作业,值仍可以为空,您应该使用Observer来检查状态。为避免这种情况,您可以使用 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;
}
当然,此解决方案的问题在于,由于它访问dabatase,因此无法在主线程上运行。但是,如果您有多个Worker,但一次只能运行一个,或者由于某种原因一个Worker需要安排另一个,那么这种解决方案就很好。
编辑: 似乎 SynchronousWorkManager 已于10月11日删除:
删除了WorkManager.synchronous()和WorkContinuation.synchronous()以及所有相关方法。在API中添加了ListenableFuture作为许多方法的返回类型。这是一个重大的API更改。
如何使用它:
您现在可以使用ListenableFutures同步获取和观察。例如,WorkManager.enqueue()用于返回void;现在它返回一个ListenableFuture。操作完成后,您可以调用ListenableFuture.addListener(Runnable,Executor)或ListenableFuture.get()来运行代码。
更多信息here。
答案 2 :(得分:2)
以及 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 :(得分:0)
如果您正在使用Kotlin,则可以编写这样的扩展功能
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
}
}
答案 4 :(得分:0)
我在这篇文章中找到了答案,并进行了一些编辑。
在我的项目中;我每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");
}
}
答案 5 :(得分:0)
接受的答案是错误的(很糟糕,因为它默默地失败了)。 这是正确答案
include_directories(${Boost_INCLUDE_DIRS})
除了一些重构以避免误导多个返回之外,错误就在这一行
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。