Skip to content

Commit a8d15ca

Browse files
Prevent duplicate startup work scheduling
1 parent 31e7acb commit a8d15ca

File tree

2 files changed

+46
-0
lines changed

2 files changed

+46
-0
lines changed

app/src/main/java/com/d4rk/androidtutorials/java/startup/StartupInitializer.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,21 @@
33
import android.content.Context;
44

55
import androidx.annotation.NonNull;
6+
import androidx.annotation.VisibleForTesting;
67
import androidx.work.ExistingWorkPolicy;
78
import androidx.work.OneTimeWorkRequest;
89
import androidx.work.WorkManager;
910

11+
import java.util.concurrent.atomic.AtomicBoolean;
12+
1013
/**
1114
* Helper used to enqueue a one-off background job for initializing ads and
1215
* cookies. The work is only scheduled once per app launch sequence.
1316
*/
1417
public final class StartupInitializer {
1518

1619
private static final String WORK_NAME = "startup_init";
20+
private static final AtomicBoolean HAS_SCHEDULED = new AtomicBoolean(false);
1721

1822
private StartupInitializer() {
1923
// no-op
@@ -24,10 +28,19 @@ private StartupInitializer() {
2428
* is already enqueued, this call is ignored.
2529
*/
2630
public static void schedule(@NonNull Context context) {
31+
if (!HAS_SCHEDULED.compareAndSet(false, true)) {
32+
return;
33+
}
34+
2735
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(
2836
StartupWorker.class).build();
2937
WorkManager.getInstance(context).enqueueUniqueWork(
3038
WORK_NAME, ExistingWorkPolicy.KEEP, workRequest);
3139
}
40+
41+
@VisibleForTesting
42+
static void resetForTesting() {
43+
HAS_SCHEDULED.set(false);
44+
}
3245
}
3346

app/src/test/java/com/d4rk/androidtutorials/java/startup/StartupInitializerTest.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import androidx.work.OneTimeWorkRequest;
77
import androidx.work.WorkManager;
88

9+
import org.junit.After;
10+
import org.junit.Before;
911
import org.junit.Test;
1012
import org.mockito.MockedStatic;
1113

@@ -14,9 +16,20 @@
1416
import static org.mockito.Mockito.mock;
1517
import static org.mockito.Mockito.mockStatic;
1618
import static org.mockito.Mockito.verify;
19+
import static org.mockito.Mockito.verifyNoMoreInteractions;
1720

1821
public class StartupInitializerTest {
1922

23+
@Before
24+
public void setUp() {
25+
StartupInitializer.resetForTesting();
26+
}
27+
28+
@After
29+
public void tearDown() {
30+
StartupInitializer.resetForTesting();
31+
}
32+
2033
@Test
2134
public void schedule_enqueuesWorkWithKeepPolicy() {
2235
Context context = mock(Context.class);
@@ -34,4 +47,24 @@ public void schedule_enqueuesWorkWithKeepPolicy() {
3447
);
3548
}
3649
}
50+
51+
@Test
52+
public void schedule_multipleCalls_enqueuesWorkOnlyOnce() {
53+
Context context = mock(Context.class);
54+
WorkManager workManager = mock(WorkManager.class);
55+
56+
try (MockedStatic<WorkManager> mockedWorkManager = mockStatic(WorkManager.class)) {
57+
mockedWorkManager.when(() -> WorkManager.getInstance(context)).thenReturn(workManager);
58+
59+
StartupInitializer.schedule(context);
60+
StartupInitializer.schedule(context);
61+
62+
verify(workManager).enqueueUniqueWork(
63+
eq("startup_init"),
64+
eq(ExistingWorkPolicy.KEEP),
65+
any(OneTimeWorkRequest.class)
66+
);
67+
verifyNoMoreInteractions(workManager);
68+
}
69+
}
3770
}

0 commit comments

Comments
 (0)