JobScheduler发布作业两次(不是预期的)

我在JobScheduler上写了一个教程,我发现一个奇怪的行为。 我要求在1秒内安排3个不同的工作(.setOverrideDeadline(1000)),但是他们都提交并运行两次…所以这里的代码:

public class MyApplication extends Application { private static final int JOB_ID_HanlderThread = 100; private static final int JOB_ID_ExecutorService = 200; private static final int JOB_ID_AsyncTask = 300; JobScheduler mJobScheduler; ExecutorService myExecutorServiceForJobs=null; private static MyApplication INSTANCE; public static MyApplication getInstance(){ return INSTANCE; } /** * Called when the application is starting, before any activity, service, * or receiver objects (excluding content providers) have been created. * Implementations should be as quick as possible (for example using * lazy initialization of state) since the time spent in this function * directly impacts the performance of starting the first activity, * service, or receiver in a process. * If you override this method, be sure to call super.onCreate(). */ @Override public void onCreate() { Log.e("MyApplication", "*********************** onCreate *****************************"); super.onCreate(); //use only for the ExceutorService case INSTANCE=this; //instanciate your JobScheduler mJobScheduler= (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE); Log.e("MyApplication", "onCreate: JobScheduler instanciate"); //this first example use the HandlerThread (no need of executor service) //--------------------------------------------------------------------- //define your JobServices here JobInfo.Builder builder = new JobInfo.Builder(JOB_ID_HanlderThread, new ComponentName( getPackageName(), MyJobServiceUsingHandlerThread.class.getName() ) ); //begin in one second builder.setOverrideDeadline(1000); int returnedValue; //the return value is failure(0) or success(1) not the JobId if success (Javadoc wrong) returnedValue=mJobScheduler.schedule( builder.build() ); //launch it if( returnedValue <= 0 ) { //If something goes wrong (manage exception/error is better than logging them) Log.e("MyApplication", "onCreate: JobScheduler launch the task failure"); }else{ //nothing goes wrong Log.e("MyApplication", "onCreate: JobScheduler launch the task suceess JOB_ID_HanlderThread "+returnedValue); } //this second example use ExecutorService //--------------------------------------- //then again define your Job and launch it JobInfo.Builder builder1 = new JobInfo.Builder(JOB_ID_ExecutorService, new ComponentName( getPackageName(), MyJobServiceUsingExecutor.class.getName() ) ); //begin in one second builder1.setOverrideDeadline(1000); //launch it returnedValue=mJobScheduler.schedule( builder1.build() ); if( returnedValue <= 0 ) { //If something goes wrong (manage exception/error is better than logging them) Log.e("MyApplication", "onCreate: JobScheduler launch the task failure"); }else{ //nothing goes wrong Log.e("MyApplication", "onCreate: JobScheduler launch the task suceess JOB_ID_ExecutorService "+returnedValue); } //this third example use AsyncTask //-------------------------------- //then again define your Job and launch it JobInfo.Builder builder2 = new JobInfo.Builder(JOB_ID_AsyncTask, new ComponentName( getPackageName(), MyJobServiceUsingAsyncTask.class.getName() ) ); //begin in one second builder2.setOverrideDeadline(1000); //launch it returnedValue=mJobScheduler.schedule( builder2.build() ); if( returnedValue <= 0 ) { //If something goes wrong (manage exception/error is better than logging them) Log.e("MyApplication", "onCreate: JobScheduler launch the task failure"); }else{ //nothing goes wrong Log.e("MyApplication", "onCreate: JobScheduler launch the task suceess JOB_ID_AsyncTask "+returnedValue); } } 

使用这段代码,我希望我的作业运行一次,但是如果我查看我获得的日志:

 10-20 06:45:13.118 13041-13041/? E/MyApplication: *********************** onCreate ***************************** 10-20 06:45:13.122 13041-13041/? E/MyApplication: onCreate: JobScheduler instanciate 10-20 06:45:13.126 13041-13041/? E/MyApplication: onCreate: JobScheduler launch the task suceess JOB_ID_HanlderThread 1 10-20 06:45:13.127 13041-13041/? E/MyApplication: onCreate: JobScheduler launch the task suceess JOB_ID_ExecutorService 1 10-20 06:45:13.130 13041-13041/? E/MyApplication: onCreate: JobScheduler launch the task suceess JOB_ID_AsyncTask 1 10-20 06:45:13.559 13041-13041/? E/MyJobServiceHandler: onStartJob called <-------------------------------- 10-20 06:45:13.572 13041-13041/? E/MyJobServiceExecutor: onStartJob called <-------------------------------- 10-20 06:45:14.133 13041-13041/? E/MyJobServiceAsync: onStartJob called <-------------------------------- 10-20 06:45:14.141 13041-13041/? E/MyJobServiceAsync: onStartJob called <-------------------------------- 10-20 06:45:18.571 13041-13066/? E/MyHandler: The work is done in a separate thread called MyJobServiceUsingHandlerThread 10-20 06:45:18.573 13041-13041/? E/MyJobServiceHandler: onDestroy called, Looper is dead <****************************************** 10-20 06:45:18.574 13041-13041/? E/MyJobServiceHandler: onStartJob called <-------------------------------- 10-20 06:45:18.576 13041-13067/? E/MyRunnable: The work is done in a separate thread called MyJobServiceUsingExecutorService 10-20 06:45:18.577 13041-13041/? E/MyJobServiceExecutor: onDestroy called, executor service is dead <****************************************** 10-20 06:45:18.577 13041-13041/? E/MyApplication: killMyExecutorServiceForJob called 10-20 06:45:18.577 13041-13041/? E/MyApplication: myExecutorServiceForJobs isShutDown 10-20 06:45:18.580 13041-13041/? E/MyJobServiceExecutor: onStartJob called <-------------------------------- 10-20 06:45:19.145 13041-13070/? E/MyAsyncTask: The work is done in a separate thread called AsyncTask #1 10-20 06:45:19.145 13041-13041/? E/MyAsyncTask: The work is finished <****************************************** 10-20 06:45:23.576 13041-13075/? E/MyHandler: The work is done in a separate thread called MyJobServiceUsingHandlerThread 10-20 06:45:23.577 13041-13041/? E/MyJobServiceHandler: onDestroy called, Looper is dead <****************************************** 10-20 06:45:23.582 13041-13076/? E/MyRunnable: The work is done in a separate thread called MyJobServiceUsingExecutorService 10-20 06:45:23.584 13041-13041/? E/MyJobServiceExecutor: onDestroy called, executor service is dead <****************************************** 10-20 06:45:23.584 13041-13041/? E/MyApplication: killMyExecutorServiceForJob called 10-20 06:45:23.584 13041-13041/? E/MyApplication: myExecutorServiceForJobs isShutDown 10-20 06:45:24.147 13041-13077/? E/MyAsyncTask: The work is done in a separate thread called AsyncTask #2 10-20 06:45:24.148 13041-13041/? E/MyAsyncTask: The work is finished <****************************************** 

我在教程中做的是使用HandlerThread运行一个Job,使用ExecutorService运行另一个Job,最后使用AsyncTask解释如何在后台线程中完成工作。 我展示了这种不同的技术,因为可能存在用于将作业排入同一个线程(HandlerThread)或pipe理Thread(ExecutorService)池或仅使用非托pipe线程(AsyncTask)的用例。

我定义了作业并在MyApplication:onCreate方法中安排它们。 为了深入了解代码,我把它放在GitHub上: https : //github.com/MathiasSeguy-Android2EE/JobSchedulerForGitHub

Solutions Collecting From Web of "JobScheduler发布作业两次(不是预期的)"

感谢这个 – 我在JobScheduler上工作。 根据你的应用程序(谢谢!),我设法很容易地复制这个bug,并追踪错误的原因。

tl; dr,这是一个在教程应用程序之外不会经常发生的情况。 要在您的教程中解决该问题,请将作业的截止date增加到大于每个后台线程运行的时间。

正在发生的事情是,你连续安排你的工作,而JobScheduler几乎立即按照计划运行它们。 然而,一秒钟之后(一秒钟是“真实”应用程序不会发生的部分),重写期限警报触发,作业调度程序非常积极地决定任何截止date已过的作业需要重新运行(API合同规定“最后期限到期”胜过所有其他的考虑),所以它把它放入待决队列。 一旦执行的作业完成,挂起的队列被检查,并且有一个工作,所以它运行。

所以,如果截止date到期,工作正在运行,工作将会激发两次。 确保截止date在作业运行之前(导致作业正在运行)或之后(警报不会真正落到作业已完成的b / c)之后到期,并且一切按预期运行。

我已经在Android N中解决了这个问题(不幸的是M已经出货了),并且增加了CTStesting以确保它保持不变。 感谢您的关注