Docs Menu
Docs Home
/ /
Atlas Device SDKs
/ /

Bundle a Realm File - Java SDK

On this page

  • Overview
  • Create a Realm File for Bundling
  • Bundle a Realm File in Your Production Application
  • Open a Realm from a Bundled Realm File

Note

Bundle Synchronized Realms

SDK version 10.9.0 introduced the ability to bundle synchronized realms. Before version 10.9.0, you could only bundle local realms.

Realm supports bundling realm files. When you bundle a realm file, you include a database and all of its data in your application download.

This allows users to start applications for the first time with a set of initial data. For synced realms, bundling can avoid a lengthy initial download the first time a user opens your application. Instead, users must only download the synced changes that occurred since you generated the bundled file.

Important

Bundling Synced Realms

If your backend application uses Flexible Sync, users could experience a client reset the first time they open the bundled realm file. This can occur when client maximum offline time is enabled (client maximum offline time is enabled by default). If the bundled realm file was generated more than the number of days specified by the client maximum offline time setting before the user syncs for the first time, the user experiences a client reset.

Applications that perform a client reset download the full state of the realm from the application backend. This negates the advantages of bundling a realm file. To prevent client resets and preserve the advantages of realm file bundling:

  • Avoid using a client maximum offline time in applications that bundle a synchronized realm.

  • If your application does use a client maximum offline time, ensure that your application download always includes a recently synced realm file. Generate a new file each application version, and ensure that no version ever stays current for more than client maximum offline time number of days.

To create and bundle a realm file with your application:

  1. Create a realm file that contains the data you'd like to bundle.

  2. Bundle the realm file in the /<app name>/src/main/assets folder of your production application.

  3. In your production application, open the realm from the bundled asset file. For synced realms, you must supply the partition key.

Note

Same-Type Sync Only

This method only supports copying a Partition-Based Sync configuration for another Partition-Based Sync user, or a Flexible Sync configuration for another Flexible Sync user. You cannot use this method to convert between a Partition-Based Sync realm and a Flexible Sync realm or vice-versa.

  1. Build a temporary realm app that shares the data model of your application.

  2. Open a realm and add the data you wish to bundle. If using a synchronized realm, allow time for the realm to fully sync.

  3. Use the writeCopyTo() method to copy the realm to a new file:

    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() { @Override 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() automatically compacts your realm to the smallest possible size before copying.

    Tip

    Differences Between Synced Realms and Local-only Realms

    The above example uses a SyncConfiguration to configure a synchronized realm. To create a copy of a local realm, configure your realm with RealmConfiguration instead.

Now that you have a copy of the realm that contains the initial data, bundle it with your production application.

  1. Search your application logs to find the location of the realm file copy you just created.

  2. Using the "Device File Explorer" widget in the bottom right of your Android Studio window, navigate to the file.

  3. Right click on the file and select "Save As". Navigate to the /<app name>/src/main/assets folder of your production application. Save a copy of the realm file there.

Tip

Asset Folders

If your application does not already contain an asset folder, you can create one by right clicking on your top-level application folder (<app name>) in Android Studio and selecting New > Folder > Assets Folder in the menu.

Now that you have a copy of the realm included with your production application, you need to add code to use it. Use the assetFile() method when configuring your realm to open the realm from the bundled file:

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

Differences Between Synced Realms and Local-only Realms

The above example uses a SyncConfiguration to configure a synchronized realm. To create a copy of a local realm, configure your realm with RealmConfiguration instead.

Back

Open & Close a Realm