如何检查
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();
}
有什么解决办法吗?
如果您只是因为不想重复工作而需要检查已经运行的工作管理器。您可以简单地使用 enqueueUniquePeriodicWork()
此方法允许您将唯一命名的 periodicworkrequest,其中只有一个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);
}
接受的答案是错误的(很糟糕,因为它默默地失败了)。 这是正确答案
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。
从 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;
}
自 10 月 11 日(2018 年)起,您可以使用 ListenableFuture 代替已删除的 SynchronousWorkManager:
您现在可以使用 ListenableFutures 同步获取和观察。例如,WorkManager.enqueue()用于返回void;它现在返回一个 ListenableFuture。操作完成后,您可以调用 ListenableFuture.addListener(Runnable, Executor) 或 ListenableFuture.get() 来运行代码。
更多信息可以在这里找到。
另一个选项可以使用 ListenableWorker:
WorkManager 中可以异步执行工作的类。对于大多数情况,我们建议使用 Worker,它提供了一个简单的同步 API,在预先指定的后台线程上执行。
调用 startWork() 函数后,它会返回 ListenableFuture。
更多信息可以在这里找到。
我在这篇文章中找到了答案,并做了一些编辑。
在我的项目中;我每 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");
}
}
我认为我们应该通过 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
}
如果工作经理已安排
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()
这应该做:
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);
}