在背景中同步 Realm - Java SDK
如果您需要在应用未运行时同步数据,您可以在背景进程中同步 Realm。
先决条件
要开始后台同步,您需要将以下依赖项添加到您的 Android 应用程序中:
androidx.work:work-runtime ,将作业排入队列
androidx.concurrent:concurrent-futures ,从背景工作线程返回作业结果
例子
背景同步需要满足两个条件:
同步逻辑
定期执行该逻辑的计划作业。
同步逻辑
首先,编写同步 Realm 的自定义逻辑。 将此逻辑视为与后端的独立运行的实例连接。因此,您需要:
初始化 Realm 软件开发工具包(Realm SDK)
对用户进行身份验证以打开 Realm
如果用户最近使用过该应用,则可以使用缓存的用户档案。
打开 域,然后使用SyncSession.downloadAllServerChanges() 和SyncSession.uploadAllLocalChanges()将 域 与后端完全同步。
您可以使用 ListenableWorker 的子类将此逻辑作为背景进程执行 。将同步逻辑放入工作线程的 startWork()
方法中:
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
要创建定期执行背景同步的工作线程:
创建一组约束,指定工作线程所需的条件。
指定工作线程的执行频率。
使用 Android 操作系统对您的工作线程进行排队。 为其分配唯一标识符,以便将来更新作业。
您可以在应用程序的应用程序子类内创建背景同步作业,以保证每次运行应用程序时逻辑仅执行一次。
由于同步域会使用数据,因此应考虑仅当设备未启动时在背景下载更改:
电池电量低
使用计量数据源
使用 约束 来描述背景同步运行的环境。
重复间隔取决于 Realm 中数据更新的频率以及用户打开应用程序的频率。 如果域全天频繁更新,请考虑将重复间隔设置为 1-3 小时。如果域每天仅更新少量内容,则最好设置较高的重复间隔,并且每天仅进行一到两次背景同步。
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 )