我有一个我想要运行的定期工作,它是在Evernote的Android Job库的帮助下实现的。
我希望实现的是每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)
at com.mydomain.myapp.service.locationUpdate.LocationUpdateJob.schedule(SourceFile:33)
at com.mydomain.myapp.activities.HubActivity.onLoginSuccess(SourceFile:173)
at com.mydomain.myapp.activities.HubActivity.onCreate(SourceFile:115)
at android.app.Activity.performCreate(Activity.java:6912)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1126)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2900)
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)
这是我的代码:
应用类
@Override
public void onCreate() {
//init things....
JobManager
.create(this)
.addJobCreator(new LocationUpdateJobCreator());
}
LocationUpdateJobCreator
public class LocationUpdateJobCreator implements JobCreator {
@Override
public Job create(String s) {
switch (s) {
case LocationUpdateJob.TAG:
return new LocationUpdateJob();
default:
return null;
}
}
}
我的名字是:
private void onLogin() {
// do other things...
LocationUpdateJob.schedule();
}
LocationUpdateJob
public class LocationUpdateJob extends Job {
public static final String TAG = "LocationUpdateJob";
private static int jobId = -1;
public static void schedule() {
final long INTERVAL = 900000L;
final long FLEX = 300000L;
jobId = new JobRequest
.Builder(LocationUpdateJob.TAG)
.setPeriodic(INTERVAL, FLEX)
.setRequiredNetworkType(JobRequest.NetworkType.CONNECTED)
.build()
.schedule();
}
public static void stop() {
JobManager
.instance()
.cancel(jobId);
}
@NonNull
@Override
protected Result onRunJob(Params params) {
updateLocation();
return Result.SUCCESS;
}
}
我分叉了Evernote的示例项目,但他们完成了相同的步骤,但我无法弄清楚我在做什么不同。
我找到了整个事情的答案。我正在回答这个问题,因为任何其他人都面临同样的问题。
好的,所以根据我上面的逻辑,这就是发生的事情:
1)用户第一次打开应用程序,在OS中安排作业,该作业一直运行到无穷大。
2)用户关闭并再次打开应用程序,在操作系统中安排另一个作业。
3)到第101次用户打开应用程序时,现在有100个作业被安排,应用程序将安排第101个作业,这会引发异常,因为android只允许应用程序安排100个作业(在较新的OS版本中)。
那么,我该怎么做才能解决这个问题呢?
我将schedule()
修改为如下所示:
public static void schedule() {
final long INTERVAL = 900000L;
final long FLEX = 300000L;
jobId = new JobRequest
.Builder(LocationUpdateJob.TAG)
.setPeriodic(INTERVAL, 300000L)
.setRequiredNetworkType(JobRequest.NetworkType.CONNECTED)
.setPersisted(true)
.setUpdateCurrent(true)
.build()
.schedule();
}
这里有什么不同,从我预定的旧方式是:.setUpdateCurrent(true)
所以它的作用是,每次使用标记调度作业时,它都会用新作业替换具有相同标记的任何现有作业,因此只有一个作业被安排用该标记执行,即作业的标记被制作独特。
有一个非常简短和良好的解释here,请阅读它。
在WorkManager的情况下,我在.enqueue()之前添加了.beginUniqueWork(),它对我有用。
Constraints myConstraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build();
Data.Builder basicWorkerInputDataBuilder = new Data.Builder();
OneTimeWorkRequest otwRequest = new OneTimeWorkRequest.Builder(BasicOneTimeWorker.class)
.setConstraints(myConstraints).addTag("BasicOneTimeWorker")
.setInputData(basicWorkerInputDataBuilder.build());
WorkManager.getInstance().beginUniqueWork("uniqueBasicOneTimeWork",
ExistingWorkPolicy.REPLACE,
otwRequest).enqueue();
以下讨论帮助我找到了解决方案。
https://github.com/googlecodelabs/android-workmanager/issues/16