Si necesitas sincronizar datos cuando la aplicación no se esté ejecutando, puedes sincronizar los reinos en un proceso en segundo plano.
Requisitos previos
To get started with background synchronization, you need to add the following dependencies to your Android application:
androidx.work:tiempo de ejecución del trabajo, para poner en cola trabajos
androidx.concurrent:concurrent-futures, to return job results from a background worker
Ejemplo
La sincronización en segundo plano requiere dos cosas:
synchronization logic
a scheduled job that periodically performs that logic.
Lógica de sincronización
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:
inicializar el SDK de Realm
authenticate a user to open the realm
You can use a user's cached credentials if the user recently used the app.
Abre el realm, luego usa SyncSession.downloadAllServerChanges() y SyncSession.uploadAllLocalChanges() para sincronizar completamente el realm con el backend.
Puedes ejecutar esta lógica como un proceso en segundo plano usando una subclase de ListenableWorker. Coloca tu lógica de sincronización en el startWork() método de su trabajador:
import android.annotation.SuppressLint; import android.content.Context; import android.util.Log; import androidx.annotation.NonNull; import androidx.concurrent.futures.ResolvableFuture; import androidx.work.ListenableWorker; import androidx.work.WorkerParameters; import com.google.common.util.concurrent.ListenableFuture; import java.util.concurrent.TimeUnit; import io.realm.Realm; import io.realm.mongodb.App; import io.realm.mongodb.AppConfiguration; import io.realm.mongodb.Credentials; import io.realm.mongodb.User; import io.realm.mongodb.sync.SyncConfiguration; public class RealmBackgroundWorker extends ListenableWorker { static final String UNIQUE_WORK_NAME = "RealmBackgroundWorker"; private ResolvableFuture<Result> future; public RealmBackgroundWorker( Context context, WorkerParameters workerParams) { super(context, workerParams); } public ListenableFuture<Result> startWork() { future = ResolvableFuture.create(); Realm.init(this.getApplicationContext()); String appID = YOUR_APP_ID; // replace this with your App ID App app = new App(new AppConfiguration.Builder(appID).build()); Credentials credentials = Credentials.anonymous(); app.loginAsync(credentials, it -> { if (it.isSuccess()) { Log.v("EXAMPLE", "Successfully authenticated."); User user = app.currentUser(); SyncConfiguration config = new SyncConfiguration.Builder(user, "PARTITION") .build(); Realm.getInstanceAsync(config, new Realm.Callback() { public void onSuccess(Realm realm) { Log.v("EXAMPLE", "Successfully opened a realm for background synchronization."); try { app.getSync().getSession(config).downloadAllServerChanges(); app.getSync().getSession(config).uploadAllLocalChanges(); } catch (InterruptedException e) { e.printStackTrace(); } } }); } else { Log.e("EXAMPLE", "Failed login: " + it.getError().getErrorMessage()); } }); return future; } }
import android.annotation.SuppressLint import android.content.Context import android.util.Log import androidx.concurrent.futures.ResolvableFuture import androidx.work.ListenableWorker import androidx.work.WorkerParameters import com.google.common.util.concurrent.ListenableFuture import io.realm.Realm import io.realm.mongodb.App import io.realm.mongodb.AppConfiguration import io.realm.mongodb.Credentials import io.realm.mongodb.User import io.realm.mongodb.sync.SyncConfiguration import java.util.concurrent.TimeUnit class RealmBackgroundWorker(context: Context, workerParams: WorkerParameters) : ListenableWorker(context, workerParams) { private lateinit var future: ResolvableFuture<Result> override fun startWork(): ListenableFuture<Result> { future = ResolvableFuture.create() Realm.init(this.applicationContext) val appID = YOUR_APP_ID // replace this with your App ID val app = App(AppConfiguration.Builder(appID).build()) val credentials = Credentials.anonymous() app.loginAsync(credentials) { it: App.Result<User?> -> if (it.isSuccess) { Log.v("EXAMPLE", "Successfully authenticated.") val user = app.currentUser() val config = SyncConfiguration.Builder(user, "PARTITION") .build() Realm.getInstanceAsync(config, object : Realm.Callback() { override fun onSuccess(realm: Realm) { Log.v("EXAMPLE", "Successfully opened a realm for background synchronization.") try { app.sync.getSession(config).downloadAllServerChanges() app.sync.getSession(config).uploadAllLocalChanges() } catch (e: InterruptedException) { e.printStackTrace() } } }) } else { Log.e("EXAMPLE", "Failed login: " + it.error.errorMessage) } } return future } companion object { const val UNIQUE_WORK_NAME = "RealmBackgroundWorker" } }
Worker
To create a worker that periodically performs background sync:
Crea un conjunto de restricciones que especifique las condiciones necesarias para tu trabajador.
Specify how frequently your worker should execute.
Enqueue your worker with the Android OS. Assign it a unique identifier so that you can update the job in the future.
Puede crear el trabajo de sincronización en segundo plano dentro de una subclase de aplicación en su aplicación para garantizar que la lógica solo se ejecute una vez cada vez que se ejecuta su aplicación.
Dado que la sincronización de un realm utiliza datos, se debería considerar descargar sólo los cambios en segundo plano cuando el dispositivo no:
poca batería
using a metered data source
Utiliza Restricciones para describir el entorno donde se ejecuta tu sincronización en segundo plano.
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 higher repeat interval and only background sync once or twice a day.
Constraints constraints = new Constraints.Builder() .setRequiredNetworkType(NetworkType.UNMETERED) .setRequiresBatteryNotLow(true) .build(); PeriodicWorkRequest backgroundRealmSync = new PeriodicWorkRequest .Builder(RealmBackgroundWorker.class, // 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.REPLACE, backgroundRealmSync);
val constraints: Constraints = Constraints.Builder() .setRequiredNetworkType(NetworkType.UNMETERED) .setRequiresBatteryNotLow(true) .build() val backgroundRealmSync: PeriodicWorkRequest = PeriodicWorkRequest.Builder( RealmBackgroundWorker::class.java, // 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.REPLACE, backgroundRealmSync )