Skip to content

Commit

Permalink
Add scheduleAsync() to the DailyJob class for scheduling daily jobs a…
Browse files Browse the repository at this point in the history
…synchronously to avoid IO operations on the main thread, see #371
  • Loading branch information
vRallev committed Feb 8, 2018
1 parent 8e5eb30 commit b25ffd5
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 1 deletion.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 1.2.4
* Add `scheduleAsync()` to the `DailyJob` class for scheduling daily jobs asynchronously to avoid IO operations on the main thread, see #371

## 1.2.3 (2018-02-07)
* Add an `onCancel()` method to get notified when the job is canceled, see #359
* Expose the `meetsRequirements()` method to have the option to check all requirements manually, see #349
Expand Down
37 changes: 37 additions & 0 deletions library/src/main/java/com/evernote/android/job/DailyJob.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import android.support.annotation.WorkerThread;

import com.evernote.android.job.util.JobCat;
import com.evernote.android.job.util.JobPreconditions;
import com.evernote.android.job.util.support.PersistableBundleCompat;

import java.util.Calendar;
Expand Down Expand Up @@ -66,6 +67,42 @@ public static int schedule(@NonNull JobRequest.Builder baseBuilder, long startMs
return schedule(baseBuilder, true, startMs, endMs);
}

/**
* Helper method to schedule a daily job on a background thread. This is helpful to avoid IO operations
* on the main thread. For more information about scheduling daily jobs see {@link #schedule(JobRequest.Builder, long, long)}.
*
* <br>
* <br>
*
* In case of a failure an error is logged, but the application doesn't crash.
*/
public static void scheduleAsync(@NonNull JobRequest.Builder baseBuilder, long startMs, long endMs) {
scheduleAsync(baseBuilder, startMs, endMs, JobRequest.DEFAULT_JOB_SCHEDULED_CALLBACK);
}

/**
* Helper method to schedule a daily job on a background thread. This is helpful to avoid IO operations
* on the main thread. The callback notifies you about the job ID or a possible failure. For more
* information about scheduling daily jobs see {@link #schedule(JobRequest.Builder, long, long)}.
*
* @param callback The callback which is invoked after the request has been scheduled.
*/
public static void scheduleAsync(@NonNull final JobRequest.Builder baseBuilder, final long startMs, final long endMs,
@NonNull final JobRequest.JobScheduledCallback callback) {
JobPreconditions.checkNotNull(callback);
JobConfig.getExecutorService().execute(new Runnable() {
@Override
public void run() {
try {
int jobId = schedule(baseBuilder, startMs, endMs);
callback.onJobScheduled(jobId, baseBuilder.mTag, null);
} catch (Exception e) {
callback.onJobScheduled(JobRequest.JobScheduledCallback.JOB_ID_ERROR, baseBuilder.mTag, e);
}
}
});
}

/**
* Schedules the daily job only once and runs it immediately. This is helpful if you want to reuse your job
* and want to trigger the execution immediately. It's possible to schedule a daily job normally with
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ public int schedule() {

/**
* Helper method to schedule a request on a background thread. This is helpful to avoid IO operations
* on the main thread. The callback notifies you about the job ID or a possible failure.
* on the main thread.
*
* <br>
* <br>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import com.evernote.android.job.test.DummyJobs;
import com.evernote.android.job.test.JobRobolectricTestRunner;
import com.evernote.android.job.test.TestClock;
import com.evernote.android.job.util.JobLogger;

import org.junit.Before;
Expand Down Expand Up @@ -108,6 +109,44 @@ public void log(int priority, @NonNull String tag, @NonNull String message, @Nul
assertThat(specificError.get()).isEqualTo(1);
}

@Test
public void verifyJobIdAsyncDailyJob() throws Exception {
JobConfig.setClock(new TestClock());

final AtomicInteger jobId = new AtomicInteger(-2);
DailyJob.scheduleAsync(DummyJobs.createBuilder(DummyJobs.SuccessJob.class), 1000, 2000, new JobRequest.JobScheduledCallback() {
@Override
public void onJobScheduled(int id, @NonNull String tag, @Nullable Exception exception) {
jobId.set(id);
}
});

waitUntilScheduled();
assertThat(manager().getJobRequest(jobId.get())).isNotNull();
}

@Test
public void verifyErrorAsyncDailyJob() throws Exception {
JobConfig.setClock(new TestClock());

JobScheduler jobScheduler = mock(JobScheduler.class);
when(jobScheduler.schedule(any(JobInfo.class))).thenThrow(new RuntimeException("test"));
when(context().getSystemService(Context.JOB_SCHEDULER_SERVICE)).thenReturn(jobScheduler);

final AtomicReference<Exception> reference = new AtomicReference<>();

DailyJob.scheduleAsync(DummyJobs.createBuilder(DummyJobs.SuccessJob.class), 1000, 2000, new JobRequest.JobScheduledCallback() {
@Override
public void onJobScheduled(int jobId, @NonNull String tag, @Nullable Exception exception) {
assertThat(jobId).isEqualTo(JOB_ID_ERROR);
reference.set(exception);
}
});

waitUntilScheduled();
assertThat(reference.get()).isInstanceOf(RuntimeException.class);
}

private void waitUntilScheduled() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
JobConfig.getExecutorService().execute(new Runnable() {
Expand Down

0 comments on commit b25ffd5

Please sign in to comment.