androidandroid-job

Number of Evernote Android-Job periodic jobs keeps building up


Seems like the number of periodic jobs on my device (both emulator and real ones) keeps increasing when the app is updated. It dosen't matter if I install using Android Studio or first create a signed APK and then update via adb (adb install -r name.apk).

Using the command 'adb shell dumpsys jobscheduler' yields the following:

Registered jobs:
  108..:[ComponentInfo{com.google.android.apps.maps/com.google.android.apps.gmm.offline.OfflineAutoUpdateJobService},jId=2131624035,u0,R=(23:32:44,47:32:44),N=1,C=true,I=true,F=0,P=true,ANI=true]
  148..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=61,u0,R=(07:54,17:54),N=0,C=false,I=false,F=0,P=false,ANI=true]
  160..:[ComponentInfo{android/com.android.server.backup.FullBackupJob},jId=20536,u0,R=(none,none),N=2,C=true,I=true,F=0,P=false,ANI=true]
  192..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=50,u0,R=(1:30:00,1:40:00),N=0,C=false,I=false,F=0,P=false,ANI=true]
  206..:[ComponentInfo{android/com.android.server.os.BackgroundCompactionService},jId=802,u0,R=(50:21,none),N=0,C=false,I=true,F=0,P=false,ANI=true]
  215..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=60,u0,R=(37:54,47:54),N=0,C=false,I=false,F=0,P=false,ANI=true]
  262..:[ComponentInfo{com.android.providers.downloads/com.android.providers.downloads.DownloadIdleService},jId=1,u0,R=(-20:38,3:25:13),N=0,C=true,I=true,F=0,P=true,ANI=true]
  291..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=9,u0,R=(12:47,22:47),N=0,C=false,I=false,F=0,P=false,ANI=true]
  312..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=37,u0,R=(12:57,22:57),N=0,C=false,I=false,F=0,P=false,ANI=true]
  456..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=38,u0,R=(1:22:56,1:32:56),N=0,C=false,I=false,F=0,P=true,ANI=true]
  540..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=39,u0,R=(22:46,32:46),N=0,C=false,I=false,F=0,P=true,ANI=true]
  577..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=57,u0,R=(03:34,13:34),N=0,C=false,I=false,F=0,P=false,ANI=true]
  639..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=8,u0,R=(22:47,32:47),N=0,C=false,I=false,F=0,P=true,ANI=true]
  663..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=56,u0,R=(33:34,43:34),N=0,C=false,I=false,F=0,P=false,ANI=true]
  862..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=43,u0,R=(23:11,33:11),N=0,C=false,I=false,F=0,P=true,ANI=true]
  864..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=32,u0,R=(22:56,32:56),N=0,C=false,I=false,F=0,P=true,ANI=true]
  984..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=42,u0,R=(1:22:46,1:32:46),N=0,C=false,I=false,F=0,P=true,ANI=true]
  102..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=49,u0,R=(00:00,10:00),N=0,C=false,I=false,F=0,P=false,ANI=true]
  104..:[ComponentInfo{android/com.android.server.pm.BackgroundDexOptService},jId=800,u0,R=(-20:38,none),N=0,C=true,I=true,F=0,P=false,ANI=true]
  114..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=44,u0,R=(23:11,33:11),N=0,C=false,I=false,F=0,P=true,ANI=true]
  124..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=53,u0,R=(19:50,29:50),N=0,C=false,I=false,F=0,P=false,ANI=true]
  124..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=33,u0,R=(12:57,22:57),N=0,C=false,I=false,F=0,P=false,ANI=true]
  126..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=62,u0,R=(1:37:54,1:47:54),N=0,C=false,I=false,F=0,P=false,ANI=true]
  130..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=41,u0,R=(12:47,22:47),N=0,C=false,I=false,F=0,P=false,ANI=true]
  131..:[ComponentInfo{android/com.android.server.backup.KeyValueBackupJob},jId=20537,u0,R=(3:42:43,23:39:25),N=1,C=true,I=false,F=0,P=false,ANI=true]
  161..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=51,u0,R=(29:50,39:50),N=0,C=false,I=false,F=0,P=false,ANI=true]
  162..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=36,u0,R=(22:56,32:56),N=0,C=false,I=false,F=0,P=true,ANI=true]
  165..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=52,u0,R=(29:50,39:50),N=0,C=false,I=false,F=0,P=false,ANI=true]
  170..:[ComponentInfo{com.google.android.apps.maps/com.google.android.apps.gmm.offline.OfflineAutoUpdateJobService},jId=2131624034,u0,R=(17:39:42,18:09:42),N=1,C=true,I=true,F=0,P=true,ANI=true]
  171..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=54,u0,R=(1:29:50,1:39:50),N=0,C=false,I=false,F=0,P=false,ANI=true]
  175..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=47,u0,R=(30:00,40:00),N=0,C=false,I=false,F=0,P=false,ANI=true]
  197..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=58,u0,R=(1:33:34,1:43:34),N=0,C=false,I=false,F=0,P=false,ANI=true]
  208..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=34,u0,R=(1:22:56,1:32:56),N=0,C=false,I=false,F=0,P=true,ANI=true]
  209..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=10,u0,R=(1:22:57,1:32:57),N=0,C=false,I=false,F=0,P=true,ANI=true]
  213..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=48,u0,R=(30:00,40:00),N=0,C=false,I=false,F=0,P=false,ANI=true]
  215..:[ComponentInfo{android/com.android.server.MountServiceIdler},jId=808,u0,R=(17:09:17,none),N=0,C=true,I=true,F=0,P=false,ANI=true]
  218..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=55,u0,R=(33:34,43:34),N=0,C=false,I=false,F=0,P=false,ANI=true]
  225..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=31,u0,R=(22:57,32:57),N=0,C=false,I=false,F=0,P=true,ANI=true]
  242..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=35,u0,R=(22:57,32:57),N=0,C=false,I=false,F=0,P=true,ANI=true]
  252..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=40,u0,R=(22:46,32:46),N=0,C=false,I=false,F=0,P=true,ANI=true]
  255..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=59,u0,R=(37:54,47:54),N=0,C=false,I=false,F=0,P=false,ANI=true]
  258..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=45,u0,R=(19:50,29:50),N=0,C=false,I=false,F=0,P=false,ANI=true]
  266..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=46,u0,R=(1:23:11,1:33:11),N=0,C=false,I=false,F=0,P=true,ANI=true]
  268..:[ComponentInfo{my.app/com.evernote.android.job.v21.PlatformJobService},jId=7,u0,R=(22:47,32:47),N=0,C=false,I=false,F=0,P=true,ANI=true]

And I only schedule 4 different jobs when starting the application (started in an instance of a 'MyApp extends Application' class.

Also: Even if I specify that periodic jobs should NOT persist between reboots the jobs are still there after a reboot. (And yes, I have '<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />' in my manifest)

This is an example on how I schedule periodic jobs:

public static void schedulePeriodicJob() {
        int jobId = new JobRequest.Builder(TSMUSyncJob.TAG_TSMU_SYNC_PERIODIC_JOB)
                .setPeriodic(TimeUnit.MINUTES.toMillis(120), TimeUnit.MINUTES.toMillis(10))
                //.setPersisted(true)
                .build()
                .schedule();
        Log.i(TAG, "Persisted job scheduled to run every 120 minutes with 10 minutes flex. Job id: " + String.valueOf(jobId));
    }

Any ideas? Thanks, Ove


Solution

  • Persistent periodic jobs are kept forever. Every time you schedule them, even with the same tag, a new job request is created. To prevent this from happening call setUpdateCurrent(true) on the JobRequest.Builder:

    JobRequest.Builder(TSMUSyncJob.TAG_TSMU_SYNC_PERIODIC_JOB)
        .setPeriodic(TimeUnit.MINUTES.toMillis(120), TimeUnit.MINUTES.toMillis(10))
        .setUpdateCurrent(true)
        .setPersisted(true)
        .build()
        .schedule()
    

    setUpdateCurrent(true) cancels all existing job requests before creating the new one. If the old job request should be kept without creating a new one check whether a job request with the same tag already exists before scheduling:

    if (jobManager.getAllJobRequestsForTag(TAG_TSMU_SYNC_PERIODIC_JOB).isEmpty()) {
         new JobRequest.Builder(...).schedule();
    }