Sync Data in the Background - Kotlin SDK
On this page
If you need to sync data when your app isn't running, you can sync realms in a background process.
Prerequisites
To get started with background synchronization, you need to add the following dependencies to your Android application:
androidx.work:work-runtime to enqueue jobs
androidx.concurrent:concurrent-futures to return job results from a background worker
Example
Background sync requires two things:
Synchronization logic
A scheduled job that periodically performs the sync logic
Synchronization Logic
First, write the custom logic that synchronizes your realm. Treat this logic as a standalone connection to your backend. As a result, you'll need to:
Get the Realm sync configuration for your app
Authenticate a user to open the realm. You can use a user's cached credentials for a logged-in user whose refresh token has not expired.
Open the realm, then use SyncSession.downloadAllServerChanges() and SyncSession.uploadAllLocalChanges() to synchronize the realm fully with the backend. For more information, see Manage Sync Sessions.
Close the realm.
You can execute this logic as a background process using a subclass of
CoroutineWorker.
Put your synchronization logic in the doWork()
method of your worker.
package com.mongodb.app.worker import android.annotation.SuppressLint import android.content.Context import androidx.concurrent.futures.ResolvableFuture import androidx.work.CoroutineWorker import androidx.work.WorkerParameters import com.mongodb.app.app import com.mongodb.app.data.RealmSyncRepository import io.realm.kotlin.Realm import io.realm.kotlin.mongodb.syncSession class RealmBackgroundWorker(context: Context, workerParams: WorkerParameters) : CoroutineWorker(context, workerParams) { private lateinit var future: ResolvableFuture<Result> override suspend fun doWork(): Result { future = ResolvableFuture.create() // Get the realm configuration for your app val syncRepository = RealmSyncRepository { session, error -> future.setException(error) } val config = syncRepository.getRealmConfiguration() // Check if user is logged-in if (app.currentUser?.loggedIn == true) { val realm = Realm.open(config) try { realm.syncSession.downloadAllServerChanges() realm.syncSession.uploadAllLocalChanges() } catch (e: InterruptedException) { e.printStackTrace() } finally { realm.close() } return future.get() } companion object { const val UNIQUE_WORK_NAME = "RealmBackgroundWorker" } }
Worker
To create a worker that periodically performs background sync:
Create a set of Constraints that specify the conditions required for your worker. Because synchronizing a realm uses data, you should consider only downloading changes in the background when the device is not:
Low on battery
Using a metered data source
Specify how frequently your worker should execute. Your repeat interval depends on how frequently data updates in the realm and how often users open your application:
If the realm frequently updates throughout the day, consider setting a repeat interval of 1-3 hours.
If the realm only updates a small number of times each day, it's best to set a less frequent repeat interval and only background sync once or twice a day.
Enqueue your worker with the Android OS. Assign it a unique identifier so that you can update the job in the future.
Tip
You can create the background sync job inside an Application subclass in your app to guarantee that the logic only executes once every time your application runs.
// Define any constraints for the background job val constraints: Constraints = Constraints.Builder() .setRequiredNetworkType(NetworkType.UNMETERED) .setRequiresBatteryNotLow(true) .build() // Define the frequency of the background job val backgroundRealmSync = PeriodicWorkRequestBuilder<RealmBackgroundWorker>( // Repeat every 12 hours 12, TimeUnit.HOURS, // Execute job at any point during that 12-hour period 12, TimeUnit.HOURS ) .setConstraints(constraints) .build() // Enqueue the work job, replacing it with the most recent // version if we update it WorkManager.getInstance(this).enqueueUniquePeriodicWork( RealmBackgroundWorker.UNIQUE_WORK_NAME, ExistingPeriodicWorkPolicy.UPDATE, backgroundRealmSync )