Syncable
interface Syncable
Interface representing a syncable entity.
Repositories that implement this interface can be synchronized in the background by SyncWorker. The sync method should handle fetching remote data and updating the local database while emitting progress updates.
Implementation Pattern
override suspend fun sync(): Flow<SyncProgress> = flow {
emit(SyncProgress(total = 100, current = 0, message = "Starting sync"))
// Fetch from network
val data = networkDataSource.getData()
// Update local database
localDataSource.saveData(data)
emit(SyncProgress(total = 100, current = 100, message = "Sync complete"))
}Content copied to clipboard
See also
For progress reporting
For triggering sync operations
Samples
return flow {
val userId = preferencesDataSource.getUserIdOrThrow()
// Unsynced jetpacks
val unsyncedJetpacks = localDataSource.getUnsyncedJetpacks(userId)
val totalUnsyncedJetpacks = unsyncedJetpacks.size
Timber.d("Syncing $totalUnsyncedJetpacks unsynced jetpacks")
// Push updates to remote
unsyncedJetpacks.forEachIndexed { index, unsyncedJetpack ->
when (unsyncedJetpack.syncAction) {
SyncAction.UPSERT -> {
Timber.d("Syncing create/update jetpack: ${unsyncedJetpack.id}")
firebaseDataSource.createOrUpdateJetpack(
unsyncedJetpack
.toFirebaseJetpack()
.copy(
lastSynced = System.currentTimeMillis(),
),
)
}
SyncAction.DELETE -> {
firebaseDataSource.deleteJetpack(
unsyncedJetpack
.toFirebaseJetpack()
.copy(
lastSynced = System.currentTimeMillis(),
),
)
}
SyncAction.NONE -> {
// Do nothing
}
}
localDataSource.markAsSynced(unsyncedJetpack.id)
emit(
SyncProgress(
total = totalUnsyncedJetpacks,
current = index + 1,
message = "Syncing jetpacks with the cloud",
),
)
}
// Remote jetpacks
val lastSynced = localDataSource.getLatestUpdateTimestamp(userId)
val remoteJetpacks = firebaseDataSource.pullJetpacks(userId, lastSynced)
val totalRemoteJetpacks = remoteJetpacks.size
Timber.d("Syncing $totalRemoteJetpacks remote jetpacks")
// Pull updates from remote
// We pull after pushing local changes to save the local changes to the cloud first
// and avoid accidentally overwriting them with stale data
remoteJetpacks.forEachIndexed { index, remoteJetpack ->
localDataSource.upsertJetpack(remoteJetpack.toJetpackEntity())
emit(
SyncProgress(
total = totalRemoteJetpacks,
current = index + 1,
message = "Fetching jetpacks from the cloud",
),
)
}
}Content copied to clipboard