Realm ファイルのバンドル - Java SDK
注意
同期された Realm のバンドル
SDK バージョン 10.9.0 では、同期された Realm をバンドルする機能が導入されました。 バージョン 10.9.0 より前は、ローカル Realm のみをバンドルできました。
Realm は Realm ファイルのバンドルをサポートしています。 Realm ファイルをバンドルする場合、データベースとそのすべてのデータをアプリケーションのダウンロードに含めます。
これにより、ユーザーは初期データセットを使用して初めてアプリケーションを起動できます。 同期済み Realm の場合、バンドルにより、ユーザーが初めてアプリケーションを開くときに長時間かかる初期ダウンロードを回避できます。 代わりに、ユーザーは、バンドル ファイルの生成以降に発生した同期された変更のみをダウンロードする必要があります。
重要
同期された Realm のバンドル
バックエンド アプリケーションで Flexible Syncを使用している場合、バンドルされている Realm ファイルを初めて開くときにクライアントがリセットされる可能性があります。 これは、クライアント最大オフライン時間が有効になっている場合に発生する可能性があります(クライアントの最大オフライン時間はデフォルトで有効になっています)。 ユーザーが最初に同期する前に、バンドルされた Realm ファイルがクライアントの最大オフライン時間設定で指定された日数を超えて生成された場合、ユーザーはクライアントをリセットします。
クライアントリセットを実行するアプリケーションは、アプリケーション バックエンドから Realm の完全な状態をダウンロードします。 これにより、Realm ファイルをバンドルする利点が得られません。 クライアントのリセットを防ぎ、Realm ファイルのバンドルの利点を維持するには、次の手順に従います。
同期された Realm をバンドルするアプリケーションでは、クライアントの最大オフライン時間を使用しないでください。
アプリケーションがクライアントの最大オフライン時間を使用する場合は、アプリケーションのダウンロードに最近同期された Realm ファイルが常に含まれていることを確認してください。 アプリケーション バージョンごとに新しい ファイルを生成し、クライアントの最大オフライン時間数を超えてどのバージョンも最新の状態に維持します。
Overview
Realm ファイルを作成してアプリケーションにバンドルするには、次の手順に従います。
バンドルするデータを含むRealm ファイルを作成します。
Realm ファイルは本番アプリケーションの
/<app name>/src/main/assets
フォルダーにバンドルします。本番アプリケーションで、バンドルされた アセット ファイル から Realm を開きます。 同期された Realm の場合は、パーティションキーを指定する必要があります。
注意
同じタイプの同期のみ
このメソッドは、別のパーティションベースの同期ユーザーのパーティションベースの同期構成、または別の Flexible Sync ユーザーの Flexible Sync 構成のコピーのみをサポートします。 このメソッドを使用して、 パーティションベースの同期 Realm と Flexible Sync レルムの間で、またはその逆に変換することはできません。
バンドル用の Realm ファイルの作成
アプリケーションのデータモデルを共有する一時的な Realm アプリを構築します。
Realm を開き、バンドルするデータを追加します。 同期された Realm を使用する場合は、Realm が完全に同期するまで時間を待ちます。
writeCopyTo()メソッドを使用して、Realm を新しいファイルにコピーします。
String appID = YOUR_APP_ID; // replace this with your App ID App app = new App(appID); Credentials anonymousCredentials = Credentials.anonymous(); app.loginAsync(anonymousCredentials, it -> { if (it.isSuccess()) { Log.v("EXAMPLE", "Successfully authenticated anonymously."); String PARTITION = "PARTITION_YOU_WANT_TO_BUNDLE"; // you can only create realm copies on a background thread with a looper. // HandlerThread provides a Looper-equipped thread. HandlerThread handlerThread = new HandlerThread("CopyARealmHandler"); handlerThread.start(); Handler handler = new Handler(handlerThread.getLooper()); handler.post(new Thread(new Runnable() { public void run() { SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser(), PARTITION) // wait for the realm to download all data from the backend before opening .waitForInitialRemoteData() .build(); Realm realm = Realm.getInstance(config); Log.v("EXAMPLE", "Successfully opened a realm."); // write a copy of the realm you can manually copy to your production application assets File outputDir = activity.getApplicationContext().getCacheDir(); File outputFile = new File(outputDir.getPath() + "/" + PARTITION + "_bundled.realm"); // ensure all local changes have synced to the backend try { app.getSync().getSession(config).uploadAllLocalChanges(10000, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { e.printStackTrace(); } // cannot write to file if it already exists. Delete the file if already there outputFile.delete(); realm.writeCopyTo(outputFile); // search for this log line to find the location of the realm copy Log.i("EXAMPLE", "Wrote copy of realm to " + outputFile.getAbsolutePath()); // always close a realm when you're done using it realm.close(); }})); } else { Log.e("EXAMPLE", "Failed to authenticate: " + it.getError().toString()); } }); val appID: String = YOUR_APP_ID // replace this with your App ID val app = App(appID) val anonymousCredentials = Credentials.anonymous() app.loginAsync(anonymousCredentials) { it: App.Result<User?> -> if (it.isSuccess) { Log.v("EXAMPLE", "Successfully authenticated anonymously.") val PARTITION = "PARTITION_YOU_WANT_TO_BUNDLE" // you can only create realm copies on a background thread with a looper. // HandlerThread provides a Looper-equipped thread. val handlerThread = HandlerThread("CopyARealmHandler") handlerThread.start() val handler = Handler(handlerThread.looper) handler.post(Thread { val config = SyncConfiguration.Builder(app.currentUser(), PARTITION) // wait for the realm to download all data from the backend before opening .waitForInitialRemoteData() .build() val realm : Realm = Realm.getInstance(config); Log.v("EXAMPLE", "Successfully opened a realm.") // write a copy of the realm you can manually copy to your production application assets val outputDir = activity!!.applicationContext.cacheDir val outputFile = File(outputDir.path + "/" + PARTITION + "_bundled.realm") // ensure all local changes have synced to the backend try { app.sync.getSession(config) .uploadAllLocalChanges(10000, TimeUnit.MILLISECONDS) } catch (e: InterruptedException) { e.printStackTrace() } // cannot write to file if it already exists. Delete the file if already there outputFile.delete() realm.writeCopyTo(outputFile) // search for this log line to find the location of the realm copy Log.i("EXAMPLE", "Wrote copy of realm to " + outputFile.absolutePath) // always close a realm when you're done using it realm.close() }) } else { Log.e("EXAMPLE", "Failed to authenticate: ${it.error}") } } writeCopyTo()
は、コピーする前に Realm を可能な限り最小のサイズに自動的に圧縮します。Tip
同期された Realm とローカル専用 Realm の違い
上記の例では、
SyncConfiguration
を使用して同期された Realm を構成しています。 ローカル Realm のコピーを作成するには、代わりにRealmConfiguration
を使用して Realm を構成します。
本番アプリケーションでの Realm ファイルのバンドル
初期データを含む Realm のコピーが用意できたら、それを本番アプリケーションにバンドルします。
アプリケーション ログを検索して、作成した Realm ファイルのコピーの場所を見つけます。
Android Studio ウィンドウの右下にある「Device ファイル エクスプローラー」ウィジェットを使用して、 ファイルに移動します。
ファイルを右クリックし、[Save As(名前を付けて保存)] を選択します。 本番アプリケーションの
/<app name>/src/main/assets
フォルダーに移動します。 Realm ファイルのコピーをそこに保存します。
Tip
アセット フォルダー
アプリケーションにアセット フォルダーがまだ含まれていない場合は、Android Studio で最上位のアプリケーション フォルダー( <app name>
)を右クリックし、[] メニューで [ New > Folder > Assets Folderを選択します。
バンドルされた Realm ファイルから Realm を開く
本番アプリケーションに含まれる Realm のコピーが作成できたら、それを使用するためのコードを追加する必要があります。 バンドルされた ファイルからRealmを開くようにRealmを構成するときは、 assetFile()メソッドを使用します。
String appID = YOUR_APP_ID; // replace this with your App ID App app = new App(appID); Credentials anonymousCredentials = Credentials.anonymous(); app.loginAsync(anonymousCredentials, it -> { if (it.isSuccess()) { Log.v("EXAMPLE", "Successfully authenticated anonymously."); // asset file name should correspond to the name of the bundled file SyncConfiguration config = new SyncConfiguration.Builder( app.currentUser(), "PARTITION_YOU_WANT_TO_BUNDLE") .assetFile("example_bundled.realm") .build(); Realm realm = Realm.getInstance(config); Log.v("EXAMPLE", "Successfully opened bundled realm."); // read and write to the bundled realm as normal realm.executeTransactionAsync(transactionRealm -> { Frog frog = new Frog(new ObjectId(), "Asimov", 4, "red eyed tree frog", "Spike"); transactionRealm.insert(frog); expectation.fulfill(); }); } else { Log.e("EXAMPLE", "Failed to authenticate: " + it.getError().toString()); } });
val appID: String = YOUR_APP_ID // replace this with your App ID val app = App(appID) val anonymousCredentials = Credentials.anonymous() app.loginAsync(anonymousCredentials) { it: App.Result<User?> -> if (it.isSuccess) { Log.v("EXAMPLE", "Successfully authenticated anonymously.") // asset file name should correspond to the name of the bundled file val config = SyncConfiguration.Builder( app.currentUser(), "PARTITION_YOU_WANT_TO_BUNDLE") .assetFile("example_bundled.realm") .build() val realm: Realm = Realm.getInstance(config) Log.v("EXAMPLE", "Successfully opened bundled realm.") // read and write to the bundled realm as normal realm.executeTransactionAsync { transactionRealm: Realm -> val frog = Frog( ObjectId(), "Asimov", 4, "red eyed tree frog", "Spike" ) transactionRealm.insert(frog) expectation.fulfill() } } else { Log.e("EXAMPLE", "Failed to authenticate: ${it.error}") } }
Tip
同期された Realm とローカル専用 Realm の違い
上記の例では、 SyncConfiguration
を使用して同期された Realm を構成しています。 ローカル Realm のコピーを作成するには、代わりにRealmConfiguration
を使用して Realm を構成します。