aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSumir Kataria <sumir@google.com>2018-06-07 16:40:01 -0700
committerSumir Kataria <sumir@google.com>2018-06-07 16:46:40 -0700
commit4e34c1f8146c680986965fa1695cbd530b684121 (patch)
tree7a352fa9552ef2024bed88e401e72aee13f1bac2
parent97c46766591189e7ce62706ce9614ebce99a222d (diff)
downloadsupport-4e34c1f8146c680986965fa1695cbd530b684121.tar.gz
Add pruneWork(Sync) methods.
This method will prune work matching the following criteria: - Finished (succeeded, failed, cancelled) - Zero unfinished dependents This, together with cancelAll, gives the ability for people to clear jobs and solves the "observation of a growing list of jobs" problem. Change-Id: Ied5571f3d143659f5d52cc4e1983e96329e91390 Fixes: 79950952 Test: Added and ran tests.
-rw-r--r--work/workmanager/src/androidTest/java/androidx/work/impl/WorkManagerImplTest.java32
-rw-r--r--work/workmanager/src/main/java/androidx/work/SynchronousWorkManager.java15
-rw-r--r--work/workmanager/src/main/java/androidx/work/WorkManager.java14
-rw-r--r--work/workmanager/src/main/java/androidx/work/impl/WorkManagerImpl.java15
-rw-r--r--work/workmanager/src/main/java/androidx/work/impl/model/WorkSpecDao.java13
-rw-r--r--work/workmanager/src/main/java/androidx/work/impl/utils/PruneWorkRunnable.java47
6 files changed, 136 insertions, 0 deletions
diff --git a/work/workmanager/src/androidTest/java/androidx/work/impl/WorkManagerImplTest.java b/work/workmanager/src/androidTest/java/androidx/work/impl/WorkManagerImplTest.java
index 71686008903..a96c677ece4 100644
--- a/work/workmanager/src/androidTest/java/androidx/work/impl/WorkManagerImplTest.java
+++ b/work/workmanager/src/androidTest/java/androidx/work/impl/WorkManagerImplTest.java
@@ -1333,6 +1333,38 @@ public class WorkManagerImplTest {
@Test
@SmallTest
+ public void pruneFinishedWork() {
+ OneTimeWorkRequest enqueuedWork = new OneTimeWorkRequest.Builder(TestWorker.class).build();
+ OneTimeWorkRequest finishedWork =
+ new OneTimeWorkRequest.Builder(TestWorker.class).setInitialState(SUCCEEDED).build();
+ OneTimeWorkRequest finishedWorkWithUnfinishedDependent =
+ new OneTimeWorkRequest.Builder(TestWorker.class).setInitialState(SUCCEEDED).build();
+ OneTimeWorkRequest finishedWorkWithLongKeepForAtLeast =
+ new OneTimeWorkRequest.Builder(TestWorker.class)
+ .setInitialState(SUCCEEDED)
+ .keepResultsForAtLeast(999, TimeUnit.DAYS)
+ .build();
+
+ insertWorkSpecAndTags(enqueuedWork);
+ insertWorkSpecAndTags(finishedWork);
+ insertWorkSpecAndTags(finishedWorkWithUnfinishedDependent);
+ insertWorkSpecAndTags(finishedWorkWithLongKeepForAtLeast);
+
+ insertDependency(enqueuedWork, finishedWorkWithUnfinishedDependent);
+
+ mWorkManagerImpl.synchronous().pruneWorkSync();
+
+ WorkSpecDao workSpecDao = mDatabase.workSpecDao();
+ assertThat(workSpecDao.getWorkSpec(enqueuedWork.getStringId()), is(notNullValue()));
+ assertThat(workSpecDao.getWorkSpec(finishedWork.getStringId()), is(nullValue()));
+ assertThat(workSpecDao.getWorkSpec(finishedWorkWithUnfinishedDependent.getStringId()),
+ is(notNullValue()));
+ assertThat(workSpecDao.getWorkSpec(finishedWorkWithLongKeepForAtLeast.getStringId()),
+ is(nullValue()));
+ }
+
+ @Test
+ @SmallTest
public void testSynchronousCancelAndGetStatus() {
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
insertWorkSpecAndTags(work);
diff --git a/work/workmanager/src/main/java/androidx/work/SynchronousWorkManager.java b/work/workmanager/src/main/java/androidx/work/SynchronousWorkManager.java
index f01e363152a..9f633d8e3e0 100644
--- a/work/workmanager/src/main/java/androidx/work/SynchronousWorkManager.java
+++ b/work/workmanager/src/main/java/androidx/work/SynchronousWorkManager.java
@@ -21,6 +21,7 @@ import android.support.annotation.WorkerThread;
import java.util.List;
import java.util.UUID;
+import java.util.concurrent.TimeUnit;
/**
* Blocking methods for {@link WorkManager} operations. These methods are expected to be called
@@ -129,6 +130,20 @@ public interface SynchronousWorkManager {
long getLastCancelAllTimeMillisSync();
/**
+ * Prunes all eligible finished work from the internal database in a synchronous fashion.
+ * Eligible work must be finished ({@link State#SUCCEEDED}, {@link State#FAILED}, or
+ * {@link State#CANCELLED}), with zero unfinished dependents.
+ * <p>
+ * <b>Use this method with caution</b>; by invoking it, you (and any modules and libraries in
+ * your codebase) will no longer be able to observe the {@link WorkStatus} of the pruned work.
+ * You do not normally need to call this method - WorkManager takes care to auto-prune its work
+ * after a sane period of time. This method also ignores the
+ * {@link OneTimeWorkRequest.Builder#keepResultsForAtLeast(long, TimeUnit)} policy.
+ */
+ @WorkerThread
+ void pruneWorkSync();
+
+ /**
* Gets the {@link WorkStatus} of a given work id in a synchronous fashion. This method is
* expected to be called from a background thread.
*
diff --git a/work/workmanager/src/main/java/androidx/work/WorkManager.java b/work/workmanager/src/main/java/androidx/work/WorkManager.java
index 83891dccef4..5960e50fcab 100644
--- a/work/workmanager/src/main/java/androidx/work/WorkManager.java
+++ b/work/workmanager/src/main/java/androidx/work/WorkManager.java
@@ -26,6 +26,7 @@ import androidx.work.impl.WorkManagerImpl;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
+import java.util.concurrent.TimeUnit;
/**
* WorkManager is a library used to enqueue work that is guaranteed to execute after its constraints
@@ -288,6 +289,19 @@ public abstract class WorkManager {
public abstract void cancelAllWork();
/**
+ * Prunes all eligible finished work from the internal database. Eligible work must be finished
+ * ({@link State#SUCCEEDED}, {@link State#FAILED}, or {@link State#CANCELLED}), with zero
+ * unfinished dependents.
+ * <p>
+ * <b>Use this method with caution</b>; by invoking it, you (and any modules and libraries in
+ * your codebase) will no longer be able to observe the {@link WorkStatus} of the pruned work.
+ * You do not normally need to call this method - WorkManager takes care to auto-prune its work
+ * after a sane period of time. This method also ignores the
+ * {@link OneTimeWorkRequest.Builder#keepResultsForAtLeast(long, TimeUnit)} policy.
+ */
+ public abstract void pruneWork();
+
+ /**
* Gets a {@link LiveData} of the last time all work was cancelled. This method is intended for
* use by library and module developers who have dependent data in their own repository that
* must be updated or deleted in case someone cancels their work without their prior knowledge.
diff --git a/work/workmanager/src/main/java/androidx/work/impl/WorkManagerImpl.java b/work/workmanager/src/main/java/androidx/work/impl/WorkManagerImpl.java
index 5b659d1c67b..13ba38f3528 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/WorkManagerImpl.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/WorkManagerImpl.java
@@ -43,6 +43,7 @@ import androidx.work.impl.utils.CancelWorkRunnable;
import androidx.work.impl.utils.ForceStopRunnable;
import androidx.work.impl.utils.LiveDataUtils;
import androidx.work.impl.utils.Preferences;
+import androidx.work.impl.utils.PruneWorkRunnable;
import androidx.work.impl.utils.StartWorkRunnable;
import androidx.work.impl.utils.StopWorkRunnable;
import androidx.work.impl.utils.taskexecutor.TaskExecutor;
@@ -340,6 +341,7 @@ public class WorkManagerImpl extends WorkManager implements SynchronousWorkManag
}
@Override
+ @WorkerThread
public void cancelUniqueWorkSync(@NonNull String uniqueWorkName) {
assertBackgroundThread("Cannot cancelAllWorkByNameBlocking on main thread!");
CancelWorkRunnable.forName(uniqueWorkName, this).run();
@@ -351,6 +353,7 @@ public class WorkManagerImpl extends WorkManager implements SynchronousWorkManag
}
@Override
+ @WorkerThread
public void cancelAllWorkSync() {
assertBackgroundThread("Cannot cancelAllWorkSync on main thread!");
CancelWorkRunnable.forAll(this).run();
@@ -367,6 +370,18 @@ public class WorkManagerImpl extends WorkManager implements SynchronousWorkManag
}
@Override
+ public void pruneWork() {
+ mTaskExecutor.executeOnBackgroundThread(new PruneWorkRunnable(this));
+ }
+
+ @Override
+ @WorkerThread
+ public void pruneWorkSync() {
+ assertBackgroundThread("Cannot pruneWork on main thread!");
+ new PruneWorkRunnable(this).run();
+ }
+
+ @Override
public LiveData<WorkStatus> getStatusById(@NonNull UUID id) {
WorkSpecDao dao = mWorkDatabase.workSpecDao();
LiveData<List<WorkSpec.WorkStatusPojo>> inputLiveData =
diff --git a/work/workmanager/src/main/java/androidx/work/impl/model/WorkSpecDao.java b/work/workmanager/src/main/java/androidx/work/impl/model/WorkSpecDao.java
index 7d9775d380f..f08658fb088 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/model/WorkSpecDao.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/model/WorkSpecDao.java
@@ -291,4 +291,17 @@ public interface WorkSpecDao {
+ ")"
)
List<WorkSpec> getEligibleWorkForScheduling();
+
+ /**
+ * Immediately prunes eligible work from the database meeting the following criteria:
+ * - Is finished (succeeded, failed, or cancelled)
+ * - Has zero unfinished dependents
+ */
+ @Query("DELETE FROM workspec WHERE "
+ + "state IN " + COMPLETED_STATES
+ + " AND (SELECT COUNT(*)=0 FROM dependency WHERE "
+ + " prerequisite_id=id AND "
+ + " work_spec_id NOT IN "
+ + " (SELECT id FROM workspec WHERE state IN " + COMPLETED_STATES + "))")
+ void pruneFinishedWorkWithZeroDependentsIgnoringKeepForAtLeast();
}
diff --git a/work/workmanager/src/main/java/androidx/work/impl/utils/PruneWorkRunnable.java b/work/workmanager/src/main/java/androidx/work/impl/utils/PruneWorkRunnable.java
new file mode 100644
index 00000000000..bf93f4602a6
--- /dev/null
+++ b/work/workmanager/src/main/java/androidx/work/impl/utils/PruneWorkRunnable.java
@@ -0,0 +1,47 @@
+/*
+ * 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.utils;
+
+import android.support.annotation.RestrictTo;
+
+import androidx.work.impl.WorkDatabase;
+import androidx.work.impl.WorkManagerImpl;
+import androidx.work.impl.model.WorkSpecDao;
+
+/**
+ * A Runnable that prunes work in the background. Pruned work meets the following criteria:
+ * - Is finished (succeeded, failed, or cancelled)
+ * - Has zero unfinished dependents
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class PruneWorkRunnable implements Runnable {
+
+ private WorkManagerImpl mWorkManagerImpl;
+
+ public PruneWorkRunnable(WorkManagerImpl workManagerImpl) {
+ mWorkManagerImpl = workManagerImpl;
+ }
+
+ @Override
+ public void run() {
+ WorkDatabase workDatabase = mWorkManagerImpl.getWorkDatabase();
+ WorkSpecDao workSpecDao = workDatabase.workSpecDao();
+ workSpecDao.pruneFinishedWorkWithZeroDependentsIgnoringKeepForAtLeast();
+ }
+}