检查 WorkManager 是否已安排
Check if WorkManager is scheduled already
如何检查 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
class 的 onCreate()
中调用 scheduleWork()
。
即使我可以通过 this method 检查我的服务是否 运行。但是我不希望 schedule WorkManager 如果它已经被安排在预定时间消除不一致。
喜欢
if(!workManagerIsScheduled())
{
scheduleWork();
}
有什么解决办法吗?
更新
如果您只是因为不想重复工作而需要检查 运行 工作管理器。您可以简单地使用 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.
因此您无需担心作品重复。
workmanager.enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.KEEP , photoCheckWork);
- 其中 TAG 是工作管理器用来检查重复项的唯一名称。
- 您可以 choose between
ExistingPeriodicWorkPolicy.KEEP
和 ExistingPeriodicWorkPolicy.REPLACE
.
原始Post
我在没有找到任何方法时创建了这个方法。
通过 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;
}
它会 return 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);
}
自 10 月 11 日 (2018) 起,您可以使用 ListenableFuture 代替 SynchronousWorkManager,后者已被删除:
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.
可以找到更多信息 here。
另一个选项可以使用 ListenableWorker:
A class that can perform work asynchronously in WorkManager. For most cases, we recommend using Worker, which offers a simple synchronous API that is executed on a pre-specified background thread.
它 returns ListenableFuture 在你调用 startWork() 函数之后。
可以找到更多信息 here。
来自 1.0.0-alpha11 连同许多东西 WorkStatus 将不起作用,它已被删除,这是一个重大变化。 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.
更新到 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;
}
我在这个 post 中找到了答案,并进行了一些编辑。
在我的项目中;我每 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");
}
}
接受的答案是错误的(很糟糕,因为它默默地失败了)。
这是正确答案
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;
除了一些重构以避免误导多个returns,错误在这一行
running = state == WorkInfo.State.RUNNING | state == WorkInfo.State.ENQUEUED;
如果你使用这条线,你只会得到最后计算的 running
。评论建议改用运算符 =|
。即使结果是正确的,代码也会不清楚并且(稍微)次优。
|
是按位运算符,||
是逻辑运算符。我们要执行的操作是逻辑的,而不是按位的。在布尔值上,|
和 ||
给出相同的结果,但只有 ||
是快捷方式,这是我们案例中的预期行为。
此代码至少适用于 WorkManager 2.5.0 和 2.6.0。
我认为我们应该通过 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
是否已安排。
这是我安排 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
class 的 onCreate()
中调用 scheduleWork()
。
即使我可以通过 this method 检查我的服务是否 运行。但是我不希望 schedule WorkManager 如果它已经被安排在预定时间消除不一致。
喜欢
if(!workManagerIsScheduled())
{
scheduleWork();
}
有什么解决办法吗?
更新
如果您只是因为不想重复工作而需要检查 运行 工作管理器。您可以简单地使用 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.
因此您无需担心作品重复。
workmanager.enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.KEEP , photoCheckWork);
- 其中 TAG 是工作管理器用来检查重复项的唯一名称。
- 您可以 choose between
ExistingPeriodicWorkPolicy.KEEP
和ExistingPeriodicWorkPolicy.REPLACE
.
原始Post
我在没有找到任何方法时创建了这个方法。
通过 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;
}
它会 return 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);
}
自 10 月 11 日 (2018) 起,您可以使用 ListenableFuture 代替 SynchronousWorkManager,后者已被删除:
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.
可以找到更多信息 here。
另一个选项可以使用 ListenableWorker:
A class that can perform work asynchronously in WorkManager. For most cases, we recommend using Worker, which offers a simple synchronous API that is executed on a pre-specified background thread.
它 returns ListenableFuture 在你调用 startWork() 函数之后。
可以找到更多信息 here。
来自 1.0.0-alpha11 连同许多东西 WorkStatus 将不起作用,它已被删除,这是一个重大变化。 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.
更新到 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;
}
我在这个 post 中找到了答案,并进行了一些编辑。
在我的项目中;我每 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");
}
}
接受的答案是错误的(很糟糕,因为它默默地失败了)。 这是正确答案
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;
除了一些重构以避免误导多个returns,错误在这一行
running = state == WorkInfo.State.RUNNING | state == WorkInfo.State.ENQUEUED;
如果你使用这条线,你只会得到最后计算的 running
。评论建议改用运算符 =|
。即使结果是正确的,代码也会不清楚并且(稍微)次优。
|
是按位运算符,||
是逻辑运算符。我们要执行的操作是逻辑的,而不是按位的。在布尔值上,|
和 ||
给出相同的结果,但只有 ||
是快捷方式,这是我们案例中的预期行为。
此代码至少适用于 WorkManager 2.5.0 和 2.6.0。
我认为我们应该通过 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
}