public class

Schedulers

extends java.lang.Object

 java.lang.Object

↳androidx.work.impl.Schedulers

Gradle dependencies

compile group: 'androidx.work', name: 'work-runtime', version: '2.10.0-alpha03'

  • groupId: androidx.work
  • artifactId: work-runtime
  • version: 2.10.0-alpha03

Artifact androidx.work:work-runtime:2.10.0-alpha03 it located at Google repository (https://maven.google.com/)

Overview

Helper methods for Schedulers. Helps schedule WorkSpecs while enforcing Scheduler.MAX_SCHEDULER_LIMITs.

Summary

Fields
public static final java.lang.StringGCM_SCHEDULER

Methods
public static voidregisterRescheduling(java.util.List<Scheduler> schedulers, Processor processor, java.util.concurrent.Executor executor, WorkDatabase workDatabase, Configuration configuration)

Make sure that once worker has run its dependants are run.

public static voidschedule(Configuration configuration, WorkDatabase workDatabase, java.util.List<Scheduler> schedulers)

Schedules WorkSpecs while honoring the Scheduler.MAX_SCHEDULER_LIMIT.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Fields

public static final java.lang.String GCM_SCHEDULER

Methods

public static void registerRescheduling(java.util.List<Scheduler> schedulers, Processor processor, java.util.concurrent.Executor executor, WorkDatabase workDatabase, Configuration configuration)

Make sure that once worker has run its dependants are run.

public static void schedule(Configuration configuration, WorkDatabase workDatabase, java.util.List<Scheduler> schedulers)

Schedules WorkSpecs while honoring the Scheduler.MAX_SCHEDULER_LIMIT.

Parameters:

workDatabase: The WorkDatabase.
schedulers: The java.util.List of Schedulers to delegate to.

Source

/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.work.impl;

import static androidx.work.impl.Scheduler.MAX_GREEDY_SCHEDULER_LIMIT;
import static androidx.work.impl.WorkManagerImpl.CONTENT_URI_TRIGGER_API_LEVEL;
import static androidx.work.impl.utils.PackageManagerHelper.setComponentEnabled;

import android.content.Context;
import android.os.Build;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.work.Clock;
import androidx.work.Configuration;
import androidx.work.Logger;
import androidx.work.impl.background.systemalarm.SystemAlarmScheduler;
import androidx.work.impl.background.systemalarm.SystemAlarmService;
import androidx.work.impl.background.systemjob.SystemJobScheduler;
import androidx.work.impl.background.systemjob.SystemJobService;
import androidx.work.impl.model.WorkSpec;
import androidx.work.impl.model.WorkSpecDao;

import java.util.List;
import java.util.concurrent.Executor;

/**
 * Helper methods for {@link Scheduler}s.
 *
 * Helps schedule {@link androidx.work.impl.model.WorkSpec}s while enforcing
 * {@link Scheduler#MAX_SCHEDULER_LIMIT}s.
 *
 */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class Schedulers {

    public static final String GCM_SCHEDULER = "androidx.work.impl.background.gcm.GcmScheduler";
    private static final String TAG = Logger.tagWithPrefix("Schedulers");

    /**
     * Make sure that once worker has run its dependants are run.
     */
    public static void registerRescheduling(
            @NonNull List<Scheduler> schedulers,
            @NonNull Processor processor,
            @NonNull Executor executor,
            @NonNull WorkDatabase workDatabase,
            @NonNull Configuration configuration) {
        processor.addExecutionListener((id, needsReschedule) -> {
            executor.execute(() -> {
                // Try to schedule any newly-unblocked workers, and workers requiring rescheduling
                // (such as periodic work using AlarmManager). This code runs after runWorker()
                // because it should happen in its own transaction.

                // Cancel this work in other schedulers. For example, if this work was
                // handled by GreedyScheduler, we should make sure JobScheduler is informed
                // that it should remove this job and AlarmManager should remove all related alarms.
                for (Scheduler scheduler : schedulers) {
                    scheduler.cancel(id.getWorkSpecId());
                }
                Schedulers.schedule(configuration, workDatabase, schedulers);
            });
        });
    }

    /**
     * Schedules {@link WorkSpec}s while honoring the {@link Scheduler#MAX_SCHEDULER_LIMIT}.
     *
     * @param workDatabase The {@link WorkDatabase}.
     * @param schedulers   The {@link List} of {@link Scheduler}s to delegate to.
     */
    public static void schedule(
            @NonNull Configuration configuration,
            @NonNull WorkDatabase workDatabase,
            @Nullable List<Scheduler> schedulers) {
        if (schedulers == null || schedulers.size() == 0) {
            return;
        }

        WorkSpecDao workSpecDao = workDatabase.workSpecDao();
        List<WorkSpec> eligibleWorkSpecsForLimitedSlots;
        List<WorkSpec> allEligibleWorkSpecs;

        workDatabase.beginTransaction();
        try {
            List<WorkSpec> contentUriWorkSpecs = null;
            if (Build.VERSION.SDK_INT >= CONTENT_URI_TRIGGER_API_LEVEL) {
                contentUriWorkSpecs = workSpecDao.getEligibleWorkForSchedulingWithContentUris();
                markScheduled(workSpecDao, configuration.getClock(), contentUriWorkSpecs);
            }

            // Enqueued workSpecs when scheduling limits are applicable.
            eligibleWorkSpecsForLimitedSlots = workSpecDao.getEligibleWorkForScheduling(
                    configuration.getMaxSchedulerLimit());
            markScheduled(workSpecDao, configuration.getClock(), eligibleWorkSpecsForLimitedSlots);
            if (contentUriWorkSpecs != null) {
                eligibleWorkSpecsForLimitedSlots.addAll(contentUriWorkSpecs);
            }

            // Enqueued workSpecs when scheduling limits are NOT applicable.
            allEligibleWorkSpecs = workSpecDao.getAllEligibleWorkSpecsForScheduling(
                    MAX_GREEDY_SCHEDULER_LIMIT);
            workDatabase.setTransactionSuccessful();
        } finally {
            workDatabase.endTransaction();
        }

        if (eligibleWorkSpecsForLimitedSlots.size() > 0) {

            WorkSpec[] eligibleWorkSpecsArray =
                    new WorkSpec[eligibleWorkSpecsForLimitedSlots.size()];
            eligibleWorkSpecsArray =
                    eligibleWorkSpecsForLimitedSlots.toArray(eligibleWorkSpecsArray);

            // Delegate to the underlying schedulers.
            for (Scheduler scheduler : schedulers) {
                if (scheduler.hasLimitedSchedulingSlots()) {
                    scheduler.schedule(eligibleWorkSpecsArray);
                }
            }
        }

        if (allEligibleWorkSpecs.size() > 0) {
            WorkSpec[] enqueuedWorkSpecsArray = new WorkSpec[allEligibleWorkSpecs.size()];
            enqueuedWorkSpecsArray = allEligibleWorkSpecs.toArray(enqueuedWorkSpecsArray);
            // Delegate to the underlying schedulers.
            for (Scheduler scheduler : schedulers) {
                if (!scheduler.hasLimitedSchedulingSlots()) {
                    scheduler.schedule(enqueuedWorkSpecsArray);
                }
            }
        }
    }

    @NonNull
    static Scheduler createBestAvailableBackgroundScheduler(@NonNull Context context,
            @NonNull WorkDatabase workDatabase, Configuration configuration) {

        Scheduler scheduler;

        if (Build.VERSION.SDK_INT >= WorkManagerImpl.MIN_JOB_SCHEDULER_API_LEVEL) {
            scheduler = new SystemJobScheduler(context, workDatabase, configuration);
            setComponentEnabled(context, SystemJobService.class, true);
            Logger.get().debug(TAG, "Created SystemJobScheduler and enabled SystemJobService");
        } else {
            scheduler = tryCreateGcmBasedScheduler(context, configuration.getClock());
            if (scheduler == null) {
                scheduler = new SystemAlarmScheduler(context);
                setComponentEnabled(context, SystemAlarmService.class, true);
                Logger.get().debug(TAG, "Created SystemAlarmScheduler");
            }
        }
        return scheduler;
    }

    @Nullable
    private static Scheduler tryCreateGcmBasedScheduler(@NonNull Context context, Clock clock) {
        try {
            Class<?> klass = Class.forName(GCM_SCHEDULER);
            Scheduler scheduler =
                    (Scheduler) klass.getConstructor(Context.class, Clock.class)
                            .newInstance(context, clock);
            Logger.get().debug(TAG, "Created " + GCM_SCHEDULER);
            return scheduler;
        } catch (Throwable throwable) {
            Logger.get().debug(TAG, "Unable to create GCM Scheduler", throwable);
            return null;
        }
    }

    private Schedulers() {
    }

    private static void markScheduled(WorkSpecDao dao, Clock clock, List<WorkSpec> workSpecs) {
        if (workSpecs.size() > 0) {
            long now = clock.currentTimeMillis();

            // Mark all the WorkSpecs as scheduled.
            // Calls to Scheduler#schedule() could potentially result in more schedules
            // on a separate thread. Therefore, this needs to be done first.
            for (WorkSpec workSpec : workSpecs) {
                dao.markWorkSpecScheduled(workSpec.id, now);
            }
        }
    }
}