I would recommend Firebase JobDispatcher.
It has some advantages over AlarmManager, Jobschedular and GCMNetworkManager. 
Read this blog for details.
Usage:
Add the following to your build.gradle's dependencies section:
implementation 'com.firebase:firebase-jobdispatcher:0.8.5'
Create a new MyJobService class.
public class MyJobService extends JobService {
    @Override
    public boolean onStartJob(JobParameters job) {
        // Do some work here
        return false; // Answers the question: "Is there still work going on?"
    }
    @Override
    public boolean onStopJob(JobParameters job) {
        return false; // Answers the question: "Should this job be retried?"
    }
}
Adding it to the manifest
    <service
        android:exported="false"
        android:name=".MyJobService">
        <intent-filter>
            <action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE"/>
        </intent-filter>
    </service>
Scheduling a job
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(context));
Job myJob = dispatcher.newJobBuilder()
        // the JobService that will be called
        .setService(MyJobService.class)
        // uniquely identifies the job
        .setTag("my-unique-tag")
        // one-off job
        .setRecurring(false)
        // don't persist past a device reboot
        .setLifetime(Lifetime.UNTIL_NEXT_BOOT)
        // start between 0 and 60 seconds from now
        .setTrigger(Trigger.executionWindow(0, 60))
        // don't overwrite an existing job with the same tag
        .setReplaceCurrent(false)
        // retry with exponential backoff
        .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
        // constraints that need to be satisfied for the job to run
        .setConstraints(
                // only run on an unmetered network
                Constraint.ON_UNMETERED_NETWORK,
                // only run when the device is charging
                Constraint.DEVICE_CHARGING
        )
        .build();
dispatcher.mustSchedule(myJob);