Ad

Android Job Scheduler Only Running Jobs When App Is Open On Android M (6)

I am trying to add an Android Job Scheduler to run jobs in the background on my Xamarin Forms app but it only seems to run when I have the app open.

The job is being scheduled correctly but just not firing with the app closed. What is supposed to happen when the job fires in an external API needs to be called to get some data and then a local SQLite database needs to be updated with that data.

I am testing this on a OnePlus 2 with Android 6 (M).

Below is my job service implementation.

[Service(Name = "com.sample.JobSchedulerService", Permission = "android.permission.BIND_JOB_SERVICE")]
public class JobSchedulerService : JobService
{
    private readonly Service _service;

    public JobSchedulerService()
    {
        _service = new Service();
    }
    public override bool OnStartJob(JobParameters jobParams)
    {
        Task.Run(() =>
        {
            var updated = _service.UpdateDataAsync(54, -2);
            JobFinished(jobParams, !updated.Result);
        });

        return true;
    }

    public override bool OnStopJob(JobParameters jobParams)
    {
        return true;
    }
}

Below is the code which schedules my job.

[assembly: Xamarin.Forms.Dependency(typeof(DownloadJob))]
namespace IslamReminders.Droid.Services
{
public class DownloadJob : IDownloadJob
{
    public void ScheduleJob(int jobId, long notificationRepeatMilliseconds)
    {
        var jobBuilder = JobScheduleHelpers.CreateJobBuilderUsingJobId<JobSchedulerService>(Application.Context, jobId)
                             .SetPeriodic(notificationRepeatMilliseconds)
                             .SetPersisted(true)
                             .Build();

        var jobScheduler = (JobScheduler)Application.Context.GetSystemService(Context.JobSchedulerService);
        var scheduleResult = jobScheduler.Schedule(jobBuilder);
    }
}
}

Below is the code to call the DownloadJob to schedule the job from App.cs OnStart.

protected override void OnStart()
    {
        // Handle when your app starts
        var jobs = _dataAccess.GetJobs();

        if (jobs.Any(x => !x.IsActive))
        {
            var inactiveJobs = jobs.Where(x => x.IsActive == false);

            foreach (var job in inactiveJobs)
            {
                var notificationTimes = _dataAccess.GetNotificationTimesForJob(job.NotificationId);

                foreach (var notificationTime in notificationTimes)
                    DependencyService.Get<IDownloadJob>().ScheduleJob(job.Id, (long)notificationTime.NotificationRepeat.TotalMilliseconds);

                job.IsActive = true;
                _dataAccess.UpdateJob(job);
            }
        }
    }

I think I have everything setup correctly but just not working when the app is closed. Any help with this will be greatly appreciated.

Ad

Answer

I ended up changing my implementation to use AlarmManager as that was more appropriate for what I was trying to achieve because I needed my job to run just after midnight each day.

However, I ended up running into exactly the same issue in that my job wouldn't run when the app was closed. When the app was or open or in the background the code would run fine.

I then did some further analysis and discovered that the issue was actually to do with me trying to get the path to the database using DependencyService. The error I received is as follows:

You MUST call Xamarin.Forms.Init(); prior to using it

The reason it wasn't working when the app was closed was because Xamarin.Forms was never intialised at that point so it was not possible to use DependencyService. The way I have fixed this issue is to get the path to the database in the broadcast receiver (or JobSchedulerService) and pass that through to my shared code which then worked as expected.

I did not test this with Job Scheduler as I decided to change my implementation but I believe this may have been the with the Job Scheduler all along.

Hopefully this explanation can help somebody who may run into similar issues.

Ad
source: stackoverflow.com
Ad