Docs Menu
Docs Home
/ /
Atlas Device SDKs
/ /

Manage a Sync Session - Kotlin SDK

On this page

  • Sync Sessions
  • Connection States vs. Session States
  • Wait for Changes to Upload and Download
  • Pause and Resume a Sync Session
  • When to Pause a Sync Session
  • Monitor Network Connection
  • Manually Reconnect All Sync Sessions

This page describes sync sessions and how to manage them in an App using Flexible Sync. For detailed information on Flexible Sync, refer to Atlas Device Sync in the App Services documentation.

When you use Flexible Sync, the Realm Kotlin SDK syncs data with Atlas in the background using a sync session. The sync session starts whenever you open a synced realm.

val app = App.create(YOUR_APP_ID)
val user = app.login(credentials)
val config = SyncConfiguration.Builder(user, setOf(Task::class))
.build()
// Open the synced realm
val realm = Realm.open(config)
// Sync session is now active
// ... do something with the synced realm

The sync session manages the following:

  • Uploading and downloading changes to the realm

  • Pausing and resuming sync

  • Monitoring network connectivity

You can access the SyncSession of a single synced realm through the realm.syncSession property.

The Kotlin SDK manages communication with App Services at two levels:

  • connection state: the state of the network connection between a client device and your backend App.

  • session state: a single user's synchronization state, which can be paused and resumed in the SDK at will (refer to the Pause and Resume a Sync Session section).

Both states determine whether a user's local changes sync to the backend. Synchronization only occurs when the SyncSession.ConnectionState is CONNECTED and the SyncSession.State is either ACTIVE or DYING.

To asynchronously wait for all changes to upload to Atlas from your synced realm, call uploadAllLocalChanges. This method returns true when all changes have been uploaded.

To asynchronously wait for all changes on Atlas to download from the Device Sync server to your synced realm, call downloadAllServerChanges. This method returns true when all changes have been downloaded.

You can also include an optional timeout parameter to either method to determine the maximum amount of time before returning false. Note that the upload or download continues in the background even after returning false.

The following example demonstrates calling both methods with a timeout defined:

// Wait to download all pending changes from Atlas
realm.syncSession.downloadAllServerChanges(1.minutes)
// Add data locally
realm.write {
this.copyToRealm(Task().apply {
taskName = "Review proposal"
assignee = "Emma"
progressMinutes = 0
})
}
// Wait for local changes to be uploaded to Atlas
realm.syncSession.uploadAllLocalChanges(1.minutes)

To pause syncing for a session, call syncSession.pause(). The realm will not sync changes with Atlas while the session is paused.

To resume syncing a changes, call syncSession.resume().

You must manually call syncSession.pause() and syncSession.resume() for each realm whose Sync session you want to pause and restart. The sync state of one session has no impact on other open sessions.

The following code block demonstrates calling these methods:

// Pause the sync session
// Data that you write while session is paused does not sync to Atlas
realm.syncSession.pause()
// Add data locally
realm.write {
this.copyToRealm(Task().apply {
taskName = "Submit expense report"
assignee = "Kevin"
progressMinutes = 0
})
}
// Resume sync session
// Local changes now sync to Atlas
realm.syncSession.resume()

For most applications, there is no need to manually pause and resume a sync session. However, there are a few circumstances under which you may want to pause or suspend a sync session:

  • You only want to sync after the user takes a specific action

  • You only want to sync during a certain time of the day

  • You don't want to attempt to sync when there is poor network connectivity

  • You want to explicitly force a sync session to connect

In the case of poor network connectivity, continually trying to establish a network connection can drain the user's device battery.

The case of explicitly forcing a sync session to connect is most commonly related to being offline for some time. The sync client attempts to connect, and upon failure, goes into exponential backoff. After being offline for a long time, the client may not immediately reconnect. Pausing and resuming the sync session explicitly forces the connection.

When you do pause a sync session, keep these things in mind:

  • If the client may be offline longer than the client maximum offline time, the client will be unable to resume syncing and must perform a client reset.

  • Pausing a sync session pauses it in both directions. Changes that your app makes on the device do not sync with the backend, and changes to the data in the backend or on other devices do not sync to the device. There is no way to pause only uploads or pause only downloads.

  • Do not pause a sync session if you want a client to permanently stop syncing with the backend. To permanently stop syncing, copy the contents of the synced realm into a non-synced realm, and use the non-synced realm in the client.

Do not pause sync to stop syncing for indefinite time periods or time ranges in months and years. The functionality is not designed or tested for these use cases. You could encounter a range of issues when using it this way.

You can get the state of the current network connection by checking the SyncSession.connectionState property. This returns a ConnectionState enum value that indicates the state of the network connection. The possible states are: CONNECTED, DISCONNECTED, or CONNECTING.

if (realm.syncSession.connectionState == ConnectionState.CONNECTED) {
Log.i("Connected to network")
// ... do something
}

Monitor the state of the network connection with connectionStateAsFlow. This property returns a Flow of ConnectionStateChange objects that updates when the network connection changes. You can access the new and old ConnectionState from ConnectionStateChange.

val connectionFlow = realm.syncSession.connectionStateAsFlow()
connectionFlow.collect { ConnectionStateChange ->
if (ConnectionStateChange.newState == ConnectionState.CONNECTED) {
Log.i("Connected to Atlas Device Sync server")
}
}

New in version 1.11.0.

Realm automatically detects when a device regains connectivity after being offline and attempts to reconnect using an incremental backoff strategy.

In Kotlin SDK version 1.11.0 and later, you can choose to manually trigger a reconnect attempt with the App.Sync.reconnect() instead of waiting for the duration of the incremental backoff. This is useful if you have a more accurate understanding of the network conditions (for example, when monitoring network changes with the ConnectivityManager on Android) and don't want to rely on Realm's automatic reconnect detection. The SDK also automatically calls this method when a device toggles off airplane mode.

To manually trigger a reconnect attempt, call the App.Sync.reconnect() method, which is accessed through the App.Sync interface. Unlike SyncSession, which lets you access a single realm sync session, the App.Sync interface controls all sync sessions for your App.

app.sync.reconnect()

When you call this method, the SDK forces all sync sessions to attempt to reconnect immediately and resets any timers used for incremental backoff.

Important

Cannot Reconnect Within Socket Read Timeout Duration

Realm has an internal default socket read timeout of 2 minutes, where Realm will time out if a read operation does not receive any data within a 2-minute window. If you call App.Sync.reconnect() within that window, the Kotlin SDK does not attempt to reconnect.

Back

Write to a Synced Realm