如何正确使用WorkManagerAndroid Jetpack中的新功能来安排每天一次的定期工作,这应该每天做一次并且只做一次?
我们的想法是检查具有给定标签的工作是否已经存在WorkManager,否则开始新的定期工作.
我尝试使用下一种方法来做到这一点:
public static final String CALL_INFO_WORKER = "Call worker";
...
WorkManager workManager = WorkManager.getInstance();
List<WorkStatus> value = workManager.getStatusesByTag(CALL_INFO_WORKER).getValue();
if (value == null) {
WorkRequest callDataRequest = new PeriodicWorkRequest.Builder(CallInfoWorker.class,
24, TimeUnit.HOURS, 3, TimeUnit.HOURS)
.addTag(CALL_INFO_WORKER)
.build();
workManager.enqueue(callDataRequest);
}
Run Code Online (Sandbox Code Playgroud)
但value总是空,即使我把一个断点里面Worker的doWork()方法(所以它肯定是正在进行中),并从另一个线程检查工作状态.
android android-architecture-components android-jetpack android-workmanager
我有一个我想要运行的定期工作,它是在Evernote的Android Job库的帮助下实现的.
我希望实现的是将myMyLocation更新为15分钟.
问题是,每隔15分钟,这项工作似乎要多次执行.
我使用OnePlus3设备进行了测试,并且通过调试,我观察到
LocationUpdateJob.schedule()只调用一次,这是正确的,但是LocationUpdateJob.onRunJob()多次调用,这是不正确的,但应该每15分钟调用一次.
此外,根据崩溃分析,一些设备会抛出illegalStateExceptions.此特殊例外仅在Android 7设备上发生.
以下是崩溃报告中的崩溃:
Fatal Exception: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mydomain.myapp/MainActivity}: java.lang.IllegalStateException: Apps may not schedule more than 100 distinct jobs
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2947)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3008)
at android.app.ActivityThread.-wrap14(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1650)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6688)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
Caused by java.lang.IllegalStateException: Apps may not schedule more than 100 distinct jobs
at android.os.Parcel.readException(Parcel.java:1701)
at android.os.Parcel.readException(Parcel.java:1646)
at android.app.job.IJobScheduler$Stub$Proxy.schedule(IJobScheduler.java:158)
at android.app.JobSchedulerImpl.schedule(JobSchedulerImpl.java:42)
at com.evernote.android.job.v21.JobProxy21.schedule(SourceFile:198)
at com.evernote.android.job.v21.JobProxy21.plantPeriodic(SourceFile:92)
at com.evernote.android.job.JobManager.scheduleWithApi(SourceFile:282)
at com.evernote.android.job.JobManager.schedule(SourceFile:240)
at com.evernote.android.job.JobRequest.schedule(SourceFile:366) …Run Code Online (Sandbox Code Playgroud) By referring to: Android WorkManager api for running daily task in Background
It uses the WorkManager.enqueueUniquePeriodicWork to ensure that PeriodicWorkRequest is not created multiple times.
example code:
val work = PeriodicWorkRequestBuilder<SyncWork>(15,TimeUnit.MINUTES).build()
WorkManager.getInstance().enqueueUniquePeriodicWork("TaskTag",
ExistingPeriodicWorkPolicy.KEEP, work);
Run Code Online (Sandbox Code Playgroud)
However, I found it there is 2 option of ExistingPeriodicWorkPolicy which is ExistingPeriodicWorkPolicy.KEEP and ExistingPeriodicWorkPolicy.REPLACE can be use.
I try to implement it and run the code, but it does really show any differences, and it seem both of them behave the same way.
My uncertainty: …
对于 OneTimeWorkRequest,我们可以使用 WorkContinuation 来确保如果作业已经被安排,我们可以保留或替换它。PeriodicWorkRequest 没有这样的选项,因此每次创建我的主要活动时都会创建一个新作业,一段时间后我会收到此异常。
java.lang.IllegalStateException: Apps may not schedule more than 100 distinct jobs
Run Code Online (Sandbox Code Playgroud)
所以我正在尝试以下内容来创建一个“独特的周期性作品”
public void schedule(){
Constraints constraints = new Constraints.Builder().setRequiresBatteryNotLow(true).build();
OneTimeWorkRequest zombieSpawnWorker = new OneTimeWorkRequest.Builder(ZombieSpawnWorker
.class).setInitialDelay(15, TimeUnit.MINUTES).setConstraints(constraints).addTag(ZombieSpawnWorker.TAG).build();
this.setUuid(zombieSpawnWorker.getId());
WorkManager.getInstance().beginUniqueWork(TAG,
ExistingWorkPolicy.KEEP,
OneTimeWorkRequest.from(ZombieSpawnWorker.class));
}
Run Code Online (Sandbox Code Playgroud)
然后在工作结束时再次调用此方法
public WorkerResult doWork() {
try {
//work to be done
} catch (Exception e) {
Log.e(TAG,e.getLocalizedMessage());
return WorkerResult.FAILURE;
}
schedule();
return WorkerResult.SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)