-
public final class ReplicatorWorker extends CoroutineWorker
Implementation Notes:
Android does not support daemon processes. Although it is less likely to happen on modern phones with lots of memory, Android will still kill off a running application if it needs the memory space to run a new app. Under these circumstance, CouchbaseLite continuous replication makes sense only while an application is in the foreground. Once an application is put in the background, it will, eventually, get killed and replicators will be stopped with prejudice. They will not be restarted until a user manually restarts the app and the replication.
In addition to this issue, continuous replication is incredibly wasteful of battery. It will force a mobile device to keep its radio on: the second most expensive thing a device can do, battery-wise. Android provides a facility managing long running processes: the
WorkManager. Jobs scheduled with theWorkManagerare persistent. They are also batched across applications in order to optimize radio use. This package integrates replication into theWorkManage. It works like this: Client code schedules replication work using normalWorkManagercode, like this:val factory = MyReplicatorFactory(). WorkManager.getInstance(context).enqueue( factory.periodicWorkRequestBuilder(15L, TimeUnit.MINUTES) .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1L, TimeUnit.HOURS) .setConstraints( Constraints.Builder() .setRequiresBatteryNotLow(true) .setRequiredNetworkType(NetworkType.CONNECTED) .setRequiresStorageNotLow(true) .build() ) .build())The only novelty here is that the client code obtains an instance of a
WorkRequest.Builderusing one of the factory methodsperiodicWorkRequestBuilder()oroneShotWorkRequestBuilder()defined on a client-created subclass ofWorkManagerReplicatorFactory,MyReplicatorFactoryin the code above. These methods the are analogs of the standardPeriodicWorkRequestBuilder()andOneShotWorkRequestBuilder()extension functions and return the appropriateWorkRequest.Builderthat can be configured, built and scheduled, as any other WorkManager request.Remember, now, that the work manager may start an entirely new instance of the client application, every time it runs a new replication! None of the state from any previous instance of the application -- fields, objects, any of it -- may be available. The
ReplicatorWorker, on the other hand, needs a properly constructedReplicatorConfigurationin order to create and run a new replicator. This is why the client code creates a subclass ofWorkManagerReplicatorFactory. When the factory method from the subclass ofWorkManagerReplicatorFactory(periodicWorkRequestBuilder()oroneShotWorkRequestBuilder()) supplied theWorkRequest.Builder, it used the value of the factory defined propertytag, to store the FQN of the factory class, in the work request. TheReplicatorWorkerrecovers this class name and creates a new instance using reflection. The instance is responsible for creating a properly constructedWorkManagerReplicatorConfigurationfrom scratch and supplying it to theReplicatorWorker.A
WorkManagerReplicatorConfigurationis very similar to aReplicatorConfiguration, except that it hides properties that should be configured in theWorkManagerrequest:continuous,heartbeat,maxAttempts, andmaxAttemptWaitTime.An application can observe the status of a work manager replication by subscribing to its
LiveData. Assuming that replications processes are 1-1 with the factory defined tag (an assumption pervasive in this implementation) the client code can obtain aLiveDataobject that providesReplicatorStatusupdates for the replicator like this:val replId = MyReplicatorFactory().tag val liveData = WorkManager.getInstance(context) .getWorkInfosByTagLiveData(replId) .map { if (it.isEmpty()) { null } else { it[0].progress.toReplicatorStatus(replId) } } return liveDataThe application terminates a repeating WorkManager replication, normally, by cancelling all of the jobs for the identifying tag:
WorkManager.getInstance(context).cancelAllWorkByTag(factory.tag)
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description public classReplicatorWorker.Companion
-
Field Summary
Fields Modifier and Type Field Description private final CoroutineDispatchercoroutineContext
-
Constructor Summary
Constructors Constructor Description ReplicatorWorker(Context appContext, WorkerParameters params)
-
Method Summary
Modifier and Type Method Description CoroutineDispatchergetCoroutineContext()ListenableWorker.ResultdoWork()-
Methods inherited from class androidx.work.CoroutineWorker
getApplicationContext, getBackgroundExecutor, getId, getInputData, getNetwork, getRunAttemptCount, getTags, getTaskExecutor, getTriggeredContentAuthorities, getTriggeredContentUris, getWorkerFactory, isRunInForeground, isStopped, isUsed, setForegroundAsync, setProgressAsync, setRunInForeground, setUsed, stop -
Methods inherited from class com.couchbase.lite.internal.ReplicatorWorker
getForegroundInfo, getForegroundInfoAsync, onStopped, setForeground, setProgress, startWork -
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
-
-
Constructor Detail
-
ReplicatorWorker
ReplicatorWorker(Context appContext, WorkerParameters params)
-
-
Method Detail
-
getCoroutineContext
CoroutineDispatcher getCoroutineContext()
-
doWork
ListenableWorker.Result doWork()
-
-
-
-