banner



Error Writing File, Is Your Harddrive Almost Full? (Getdirectory)

Getting started

Prerequisites

  • Android Studio version 1.5.1 or higher
  • JDK version 7.0 or higher
  • A recent version of the Android SDK
  • Android API Level 16 or higher (Android 4.1 and above).

Note: Realm does not support Kotlin outside of Android. We do not support Eclipse as an IDE; please migrate to Android Studio.

Installation

Install Realm as a Gradle plugin.

Step 1: Add the class path dependency to the project level build.gradle file.

            buildscript {     repositories {         jcenter()     }     dependencies {         classpath "io.realm:realm-gradle-plugin:7.0.0-beta"     } }          

To follow along, be sure to be on the "Projects" view in the top left panel. Click the dropdown in the top left corner of Android Studio and select "Projects":

Select 'Project' in the view dropdown location indicated in Android Studio

On the "Projects" view, you can find the project level build.gradle file here:

Project level build.gradle file indicated in the Project panel

Step 2: Apply the realm-android plugin near the top of the application level build.gradle file.

Note: order matters! Be sure to put realm-android after the kotlin plugins, like so:

                          apply              plugin:              'com.android.application'              apply              plugin:              'kotlin-kapt'              apply              plugin:              'kotlin-android'              apply              plugin:              'kotlin-android-extensions'              apply              plugin:              'realm-android'                      

On the "Projects" view, you can find the application level build.gradle file here:

Application level build.gradle file indicated in the Project panel

Once you make these two changes, simply refresh your gradle dependencies. If you're upgrading from a version of Realm earlier than v0.88, you may also need to clean your gradle project (./gradlew clean).

Find a sample of the two modified build.gradle files here:

  • Project level build.gradle
  • Application level build.gradle

Other Build Systems

The Maven & Ant build systems are not supported. We're tracking interest in supporting them on GitHub:

  • Maven support
  • Ant support

A ProGuard configuration is provided as part of the Realm library. This means that you don't need to add any Realm specific rules to your ProGuard configuration.

Important Notes on Realm for Kotlin

This section provides a quick overview of the important things to know about using Realm with Kotlin for developers who are familiar with Realm Java. If you are new to Realm, please come back to this section after reading the rest of this page.

There are a few caveats to be aware of when using Realm with Kotlin:

  • It is important that your model classes are open.

  • Storing enums in Realm Model classes in Kotlin should be done using the following pattern:

                          enum              class              MyEnum              {              Value1              ,              Value2              }              open              class              EnumTest              :              RealmObject              ()              {              // Custom private backing field representing the enum              private              var              strField              :              String              =              MyEnum              .              Value1              .              name              // Public field exposing setting/getting the enum              var              enumField              :              MyEnum              get              ()              =              MyEnum              .              values              ().              first              {              it              .              name              ==              strField              }              set              (              value              )              {              strField              =              value              .              name              }              }              // Queries              val              results              =              realm              .              where              <              EnumTest              >().              equalTo              (              "strField"              ,              MyEnum              .              Value1              .              name              ).              findAll              ()                      

Note that queries needs to be done on the strField with String value, not the enumField which is ignored by Realm as it has no backing field.

  • Long::class.java actually returns a Class reference to long not Long. The same is true for other primitive types like Integer, Float, Double and Boolean. Choosing the correct class has implications during a migration:
            schema   .addField("field", Long::class.java) // Non-nullable   .addField("field", Long::class.javaObjectType) // Nullable   .addField("field", Long::class.javaPrimitiveType) // Non-nullable          

When Kotlin is used in a project, Realm automatically detects this and adds a number of extension methods that makes working with Kotlin easier. This includes among others:

  • Many methods that accept a class parameter in Java now have a reified variant in Kotlin, e.g. realm.where(Person.class).findAll() becomes realm.where<Person>().findAll(). Import these variants from io.realm.kotlin.*.

  • If a model class implements the RealmModel interface, default methods are now injected automatically, meaning that you can use the exact same call pattern regardless if you extends the base class RealmObject or implements the interface RealmModel.

  • The query predicate in() has a Kotlin alias named anyOf() as in is a keyword in Kotlin.

This extension library can be manually disabled by using the realm closure:

                          android              {              ...              }              realm              {              kotlinExtensionsEnabled              =              false              // Disable extensions if needed              }                      

Kotlin 1.3.0 has a bug causing kapt to fail for certain kinds of Kotlin code. This can result in errors like "Symbol not found" when compiling. This was fixed in Kotlin 1.3.20, so we recommend upgrading.

Samples

Realm lets you efficiently write your app's model layer in a safe, persistent, and fast way. Here's what it looks like:

                          // Import the Kotlin extensions for Realm.              import              io.realm.kotlin.createObject              import              io.realm.kotlin.where              // Define your model classes by extending RealmObject.              // You must annotate all classes with `open`.              open              class              Dog              (              // You can put properties in the constructor as long as              // all of them are initialized with default values. This              // ensures that an empty constructor is generated.              // All properties are by default persisted.              // Non-nullable properties must be initialized                            // with non-null values.              var              name              :              String              =              ""              ,              var              age              :              Int              =              0              ):              RealmObject              ()              open              class              Person              (              // Properties can be annotated with PrimaryKey or Index.              @PrimaryKey              var              id              :              Long              =              0              ,              var              name              :              String              =              ""              ,              var              age              :              Int              =              0              ,              // Other objects in a one-to-one relation must also subclass RealmObject.              var              dogs              :              RealmList              <              Dog              >              =              RealmList              ()              ):              RealmObject              ()              // ...              // Use Realm objects like regular Kotlin objects              val              dog              =              Dog              ()              dog              .              name              =              "Rex"              dog              .              age              =              1              // Initialize Realm (just once per application)              Realm              .              init              (              context              )              // Get a Realm instance for this thread              realm              =              Realm              .              getDefaultInstance              ()              // Query Realm for all dogs younger than 2 years old              val              puppies              =              realm              .              where              <              Dog              >().              lessThan              (              "age"              ,              2              ).              findAll              ()              puppies              .              size              // => 0 because no dogs have been added to the Realm yet              // Persist your data in a transaction              realm              .              beginTransaction              ()              val              managedDog              =              realm              .              copyToRealm              (              dog              )              // Persist unmanaged objects              val              person              =              realm              .              createObject              <              Person              >(              0              )              // Create managed objects directly              person              .              dogs              .              add              (              managedDog              )              realm              .              commitTransaction              ()              // Listeners will be notified when data changes              puppies              .              addChangeListener              {              results              ,              changeSet              ->              // Query results are updated in real time with fine grained notifications.              changeSet              .              insertions              // => [0] is added.              }              // Asynchronously update objects on a background thread              realm              .              executeTransactionAsync              (              Realm              .              Transaction              {              bgRealm              ->              // Find a dog to update.              val              dog              =              bgRealm              .              where              <              Dog              >().              equalTo              (              "age"              ,              1              .              toInt              ()).              findFirst              ()              !!              dog              .              age              =              3              // Update its age value.              },              Realm              .              Transaction              .              OnSuccess              {              // Original queries and Realm objects are automatically updated.              puppies              .              size              // => 0 because there are no more puppies younger than 2 years old              managedDog              .              age              // => 3 the dogs age is updated              })                      

See this example for a working app combining Realm and Kotlin.

Browse the Realm database

If you need help finding your app's Realm file, check this StackOverflow answer for detailed instructions.

Realm Studio

Realm Studio is our premiere developer tool, built so you can easily manage the Realm Database and Realm Platform. With Realm Studio, you can open and edit local and synced Realms, and administer any Realm Object Server instance. It supports Mac, Windows and Linux.

Realm Studio

Stetho Realm

You can also use the Stetho-Realm plugin for Stetho, an Android debug bridge for the Chrome browser created by Facebook.

Stetho-Realm is not officially maintained by Realm.

Initializing Realm

Before you can use Realm in your app, you must initialize it. This only has to be done once.

You must provide an Android context. A good place to initialize Realm is in onCreate on an application subclass:

                          class              MyApplication              :              Application              ()              {              override              fun              onCreate              ()              {              super              .              onCreate              ()              Realm              .              init              (              this              )              }              }                      

If you create your own application subclass, you must add it to the app's AndroidManifest.xml:

                          <application              android:name=              ".MyApplication"              ...              />                      

Realms

A Realm is an instance of a Realm Mobile Database container. Realms can be local or synchronized. A synchronized Realm uses the Realm Object Server to transparently synchronize its contents with other devices. While your application continues working with a synchronized Realm as if it's a local file, the data in that Realm might be updated by any device with write access to that Realm. In practice, your application works with any Realm, local or synchronized, the same way.

For a more detailed discussion about Realms, read The Realm Data Model.

Opening Realms

Open a Realm by instantiating a new Realm object. We've seen this used already in examples:

                          // Initialize Realm              Realm              .              init              (              context              )              // Get a Realm instance for this thread              val              realm              =              Realm              .              getDefaultInstance              ()                      

The getDefaultInstance method instantiates the Realm with a default RealmConfiguration.

Configuring a Realm

To control how Realms are created, use a RealmConfiguration object. The minimal configuration usable by Realm is:

                          val              config              =              RealmConfiguration              .              Builder              ().              build              ()                      

That configuration—with no options—uses the Realm file default.realm located in Context.getFilesDir. To use another configuration, you would create a new RealmConfiguration object:

                          // The RealmConfiguration is created using the builder pattern.              // The Realm file will be located in Context.getFilesDir()              // with name "myrealm.realm"              val              config              =              RealmConfiguration              .              Builder              ()              .              name              (              "myrealm.realm"              )              .              encryptionKey              (              getMyKey              ())              .              schemaVersion              (              42              )              .              modules              (              MySchemaModule              ())              .              migration              (              MyMigration              ())              .              build              ()              // Use the config              val              realm              =              Realm              .              getInstance              (              config              )                      

You can have multiple RealmConfiguration objects, so you can control the version, schema and location of each Realm independently.

                          val              myConfig              =              RealmConfiguration              .              Builder              ()              .              name              (              "myrealm.realm"              )              .              schemaVersion              (              2              )              .              modules              (              MyCustomSchema              ())              .              build              ()              val              otherConfig              =              RealmConfiguration              .              Builder              ()              .              name              (              "otherrealm.realm"              )              .              schemaVersion              (              5              )              .              modules              (              MyOtherSchema              ())              .              build              ()              val              myRealm              =              Realm              .              getInstance              (              myConfig              )              val              otherRealm              =              Realm              .              getInstance              (              otherConfig              )                      

Get the absolute path of a Realm by using Realm.getPath.

It is important to note that Realm instances are thread singletons, meaning that the static constructor will return the same instance in response to all calls from a given thread.

The default Realm

The RealmConfiguration can be saved as a default configuration. Setting a default configuration in your custom Application class makes it available in the rest of your code.

                          class              MyApplication              :              Application              ()              {              override              fun              onCreate              ()              {              super              .              onCreate              ()              // The default Realm file is "default.realm" in Context.getFilesDir();              // we'll change it to "myrealm.realm"              Realm              .              init              (              this              )              val              config              =              RealmConfiguration              .              Builder              ().              name              (              "myrealm.realm"              ).              build              ()              Realm              .              setDefaultConfiguration              (              config              )              }              }              class              MyActivity              :              Activity              ()              {              override              fun              onCreate              (              savedInstanceState              :              Bundle              ?)              {              super              .              onCreate              (              savedInstanceState              )              val              realm              =              Realm              .              getDefaultInstance              ()              // opens "myrealm.realm"              try              {              // ... Do something ...              }              finally              {              realm              .              close              ()              }              }              }                      

Opening a synchronized Realm

Read-only Realms

readOnly is only enforced in the current process. It is still possible for other processes or devices to write to readOnly Realms. Also, any write transaction against a read-only Realm will throw an IllegalStateException. This includes trying to write the schema, so that must be provided initially by some other source.

It's sometimes useful to ship a prepared Realm file with your app—you may want to bundle some shared data with your application. In many cases you don't want to accidentally modify that Realm, as the data is purely read-only. You can do this by bundling a Realm file in assets and using a readOnly configuration:

                          val              config              =              RealmConfiguration              .              Builder              ()              .              assetFile              (              "my.realm"              )              .              readOnly              ()              // It is optional, but recommended to create a module that describes the classes              // found in your bundled file. Otherwise if your app contains other classes              // than those found in the file, it will crash when opening the Realm as the              // schema cannot be updated in read-only mode.              .              modules              (              BundledRealmModule              ())              .              build              ()                      

In-memory Realms

With an inMemory configuration, you can create a Realm that runs entirely in memory without being persisted to disk.

                          val              myConfig              =              RealmConfiguration              .              Builder              ()              .              name              (              "myrealm.realm"              )              .              inMemory              ()              .              build              ()                      

In-memory Realms might still use disk space if memory is running low, but all files created by an in-memory Realm will be deleted when the Realm is closed. Creating an in-memory Realm with the same name as a persisted Realm isn't allowed—names still have to be unique.

When all in-memory Realm instances with a particular name go out of scope with no references, that frees all that Realm's data. To keep an in-memory Realm "alive" throughout your app's execution, hold onto a reference to it.

Dynamic Realms

When working with a conventional Realm, the model class is defined using RealmObject subclasses. This has a lot of benefits with regards to type safety. But sometimes, the types aren't available until runtime, e.g., during migrations, or when working with string-based data like CSV files. Dynamic Realms to the rescue!

A DynamicRealm is a variant of the conventional Realm that makes it possible to work with Realm data without using RealmObject subclasses. Instead, all access is done using Strings instead of Classes.

Opening a Dynamic Realm uses the same configuration as a conventional Realm but the Dynamic Realm ignores any configured schema, migration, and schema version.

                          val              realmConfig              =              RealmConfiguration              .              Builder              ().              build              ()              val              realm              =              DynamicRealm              .              getInstance              (              realmConfig              )              // In a DynamicRealm all objects are DynamicRealmObjects              realm              .              beginTransaction              ()              val              person              =              realm              .              createObject              (              "Person"              )              realm              .              commitTransaction              ()              // All fields are accessed using strings              val              name              =              person              .              getString              (              "name"              )              val              age              =              person              .              getInt              (              "age"              )              // An underlying schema still exists, so accessing a field              // that does not exist will throw an exception              person              .              getString              (              "I don't exist"              )              // Queries still work normally              val              persons              =              realm              .              where              (              "Person"              )              .              equalTo              (              "name"              ,              "John"              )              .              findAll              ()                      

A DynamicRealm gains flexibility at the expense of both type safety and performance; in general, you should be using normal Realms. Only use Dynamic Realms when you need that flexibility.

Closing Realms

Realm implements Closeable to take care of native memory deallocation and file descriptors, so always close your Realm instances when you're done with them.

Realm instances are reference counted—if you call getInstance twice in a thread, you need to call close twice as well. This allows you to implement Runnable classes without having to worry about which thread will execute them: simply start it with getInstance and end it with close.

For the UI thread, the easiest way is to execute realm.close in the owning component's onDestroy method. If you need to create a Looper thread other than UI, you can use this pattern:

                          class              MyThread              :              Thread              ()              {              private              var              realm              :              Realm              ?              =              null              override              fun              run              ()              {              Looper              .              prepare              ()              realm              =              Realm              .              getDefaultInstance              ()              try              {              //... Setup the handlers using the Realm instance ...              Looper              .              loop              ()              }              finally              {              realm              ?.              close              ()              }              }              }                      

For AsyncTask this is a good pattern:

                          class              MyTask              :              AsyncTask              <              Void              ,              Void              ,              Void              >()              {              override              fun              doInBackground              (              vararg              params              :              Void              ):              Void              ?              {              val              realm              =              Realm              .              getDefaultInstance              ()              try              {              // ... Use the Realm instance ...              }              finally              {              realm              .              close              ()              }              return              null              }              }                      

If you are using Thread or Runnable for short-lived tasks:

                          // Run a non-Looper thread with a Realm instance.              val              thread              =              Thread              (              Runnable              {              val              realm              =              Realm              .              getDefaultInstance              ()              try              {              // ... Use the Realm instance ...              }              finally              {              realm              .              close              ()              }              })              thread              .              start              ()                      

Realm implements the Closable interface, so you can make use of Kotlin's built-in extension method use to automatically close the Realm instance.

                          Realm              .              getDefaultInstance              ().              use              {              realm              ->              // No need to close the Realm instance manually              }                      

Auto-Refresh

If you obtain a Realm instance from a thread associated with a Looper, the Realm instance comes with an auto-refresh feature. (Android's UI thread is a Looper.) This means the Realm instance will be periodically updated to the latest version. This lets you keep your UI constantly updated with the latest content with almost no effort!

If you get a Realm instance from a thread that does not have a Looper attached, objects from that instance won't be updated until you call the waitForChange method. Holding on to an old version of your data is expensive in terms of memory and disk space, and the cost increases with the number of versions between the one being retained and the latest. This is why it is important to close the Realm instance as soon as you are done with it in the thread.

If you want to check whether your Realm instance has auto-refresh activated or not, use the isAutoRefresh method.

Models

Create Realm models by extending the RealmObject base class:

                          open              class              User              (              var              name              :              String              =              ""              ,              var              age              :              Int              =              0              ,              @Ignore              var              sessionId              :              Int              =              0              ):              RealmObject              ()                      

A Realm model class supports public, protected and private fields, as well as custom methods.

                          open              class              User              (              var              name              :              String              =              ""              ,              var              age              :              Int              =              0              ,              @Ignore              var              sessionId              :              Int              =              0              ):              RealmObject              ()              {              fun              hasLongName              ():              Boolean              {              return              name              .              length              >              7              }              }                      

It is important that your model classes are open.

Field types

Realm supports Boolean, Byte, Short, Int, Long, Float, Double, String, Date and ByteArray field types. The integer types Byte, Short, Int, and Long are all mapped to Long within Realm. In addition to those standard field types, Realm supports subclasses of RealmObject and RealmList<? extends RealmObject> to model relationships.

Required fields

The @Required annotation can be used to tell Realm to disallow null values in a field, making it required rather than optional. Only nullable types like String and Date can be annotated with @Required. If you add it to other field types, compilation will fail.

Fields with primitive types and the RealmList type are required implicitly. Fields with RealmObject type are always nullable.

Primary keys

To mark a field as a model's primary key, use the annotation @PrimaryKey. The field type must be either a string (String) or an integer (byte, short, int, long, Byte, Short, Integer, and Long). Using a string field as a primary key automatically indexes the field: the annotation @PrimaryKey on a string implicitly sets the annotation @Index. Realm doesn't support compound keys, i.e., using multiple fields as a single primary key.

Using primary keys makes it possible to use the copyToRealmOrUpdate or insertOrUpdate methods. These look for an object with a given primary key, and either updates it (if an object with that key already exists) or creates it (if the key does not exist). If you call copyToRealmOrUpdate or insertOrUpdate on a class without a primary key, an exception will be thrown.

When you use primary keys, reads (queries) will be slightly faster, but writes (creating and updating objects) will be a little slower. The changes in performance will depend on the size of your Realm's data set.

Note that Realm.createObject returns a new object with all fields set to their default values. If the object is a class with a primary key, this could create a conflict—there might be an object with that primary key set already. To avoid this, you can create an unmanaged object, set its field values, then add it to the Realm with copyToRealm or insert:

                          val              obj              =              MyObject              ()              obj              .              id              =              42              obj              .              name              =              "Fish"              realm              .              executeTransaction              {              realm              ->              // This will create a new object in Realm or throw an exception if the              // object already exists (same primary key)              // realm.copyToRealm(obj);              // This will update an existing object with the same primary key              // or create a new object if an object with no primary key = 42              realm              .              copyToRealmOrUpdate              (              obj              )              }                      

Primary keys that are String types or boxed integers (Byte, Short, Integer, and Long) can have the value null unless the @PrimaryKey annotation is combined with @Required.

Indexing properties

To index a field, use the annotation @Index. Like primary keys, this makes writes slightly slower , but makes reads faster. (It also makes your Realm file slightly larger, to store the index.) It's best to only add indexes when you're optimizing the read performance for specific situations.

You can index String, Byte, Short, Int, Long, Boolean and Date fields.

Ignoring properties

If you don't want to save a field in your model to its Realm, use the annotation @Ignore. You might do this if, for example, your input contains more fields than your model, and you don't wish to have many special cases for handling these unused data fields.

Fields marked static and transient are always ignored, and do not need the @Ignore annotation.

Counters

Realm offers MutableRealmInteger as a special integer type. MutableRealmInteger exposes an additional API that can more clearly express intent and generate better conflict resolution steps when using Synchronized Realms.

Traditionally, a counter would be implemented by reading a value, incrementing it and setting it (myObj.counter += 1). This will not work well in an asynchronous situation — for example when two clients are offline — because both parties will read a value, say 10, increment it, and store the value as 11. Eventually, when they regain connectivity and try to merge their changes, they'll agree that the counter is at 11 rather than the expected 12.

MutableRealmIntegers are backed by traditional integer types, so no migration is required when changing a field from byte, short, int or long to MutableRealmInteger.

MutableRealmInteger is not an immutable type standard like primitive number types in Kotlin. It is a live object like RealmObject, RealmResults and RealmList. This means the value contained inside the MutableRealmInteger can change when a Realm is written to. For this reason MutableRealmInteger fields must be marked final.

                          open              class              Party              (              var              guests              :              MutableRealmInteger              =              MutableRealmInteger              .              valueOf              (              0              )              ):              RealmObject              ()                      

To change the counter value, simply call counter.increment() or counter.decrement().

                          val              party              =              realm              .              where              <              Party              >().              findFirst              ()              !!              realm              .              executeTransaction              {              party              .              guests              .              get              ()              // 0              party              .              guests              .              increment              (              1              )              // 1              party              .              guests              .              decrement              (              1              )              // 0              party              .              guests              .              increment              (              5              )              // 5              party              .              guests              .              decrement              (              1              )              // 4              }                      

To reset the counter, you can assign it a new value using counter.set().

Calling set() can potentially override increment() and decrement() operations coming from other devices pr. the normal last-write-wins merge rules, so mixin these operations should only be done if lossy counters are acceptable.

                          val              party              =              realm              .              where              <              Party              >().              findFirst              ()              !!              realm              .              executeTransaction              {              party              .              guests              .              set              (              0              )              }                      

Overriding property names

The default behaviour is that Realm will use the name defined in the model class as the name to represent classes and fields internally in the Realm file. In some cases you might want to change this behaviour:

  • To support two model classes with the same simple name but in different packages.
  • To make it easier to work with cross platform schemas as naming conventions are different.
  • To use a Kotlin class name that is longer than the 57 character limit enforced by Realm.
  • To change a field name in Kotlin without forcing app users through a migration process.

In those cases you can override the name being used internally by defining a different name using the @RealmModule, @RealmClass or @RealmField annotations.

You can define a naming policy at the module level, which will affect all classes part of the module:

                          @RealmModule              (              allClasses              =              true              ,              classNamingPolicy              =              RealmNamingPolicy              .              LOWER_CASE_WITH_UNDERSCORES              ,              fieldNamingPolicy              =              RealmNamingPolicy              .              LOWER_CASE_WITH_UNDERSCORES              )              class              MyModule              {              // ...              }                      

You can define a custom name for the class or a field naming policy that will effect all fields in that class. This will override any module level settings:

                          @RealmClass              (              name              =              "__Person"              ,              fieldNamingPolicy              =              RealmNamingPolicy              .              PASCAL_CASE              )              open              class              Person              (              var              name              :              String              ?              =              null              ):              RealmObject              ()                      

You can define a custom name for a field, this will override any Class and Module level settings:

                          open              class              (              @RealmField              (              name              =              "person_name"              )              var              name              :              String              ?              =              null              ):              RealmObject              ()                      

Choosing an internal name that differs from the name used in the Kotlin model classes has the following implications:

  • Queries on a DynamicRealm must use the internal name. Queries on normal Realm instances must continue to use the name as it is defined in the Kotlin class.
  • Migrations must use the internal name when creating classes and fields.
  • Schema errors reported will use the internal names.

Note that changing the internal name does NOT affect importing data from JSON. The JSON data must still follow the names as defined in the Realm Kotlin class.

When it comes to parsing JSON using standard libraries like Moshi, GSON or Jackson, it is important to remember that these libraries define the transformation from JSON to Kotlin while setting the internal Realm names define the transformation from Kotlin to the Realm file. This means that if you want to import data into Realm from JSON using these libraries you still need to provide the annotations from both the JSON parser library and Realm.

Using Moshi, it would look something like this:

                          open              class              Person              (              @Json              (              name              =              "first_name"              )              // Name used in JSON input.              @RealmField              (              name              =              "first_name"              )              // Name used internally in the Realm file.              var              firstName              :              string              ?              =              null              // name used in Kotlin              ):              RealmObject              ()                      

See RealmNamingPolicy for more info.

Working with RealmObjects

Auto-updating objects

RealmObjects are live, auto-updating views into the underlying data; you never have to refresh objects. Changes to objects are instantly reflected in query results.

                          realm              .              executeTransaction              {              realm              ->              val              myDog              =              realm              .              createObject              <              Dog              >()              myDog              .              name              =              "Fido"              myDog              .              age              =              1              }              val              myDog              =              realm              .              where              <              Dog              >().              equalTo              (              "age"              ,              1              .              toInt              ()).              findFirst              ()              realm              .              executeTransaction              {              realm              ->              val              myPuppy              =              realm              .              where              <              Dog              >().              equalTo              (              "age"              ,              1              .              toInt              ()).              findFirst              ()              myPuppy              .              age              =              2              }              myDog              .              age              // => 2                      

This not only keeps Realm fast and efficient, it allows your code to be simpler and more reactive. If your Activity or Fragment is dependent on a specific RealmObject or RealmResults instance, you don't need worry about refreshing or re-fetching it before updating the UI.

You can subscribe to Realm notifications to know when Realm data is updated.

Customizing objects

It is possible to use a RealmObject almost like a Data Class. Extend your class from RealmObject. You can let the fields be public, and can use simple assignments instead of setters and getters.

                          open              class              Dog              (              var              name              :              String              =              ""              ,              var              age              :              Int              =              0              ):              RealmObject              ()                      

You can use Dog like any other class: you can add logic to your getter and setter methods (for example, for validation), and you can add any custom methods you wish.

To add your Dog object to a Realm, use the createObject or copyToRealm methods.

Remember that Kotlin has reified versions of methods that take a class, such as createObject(). These extensions are found by importing io.realm.kotlin.*.

                          realm              .              executeTransaction              {              realm              ->              val              dog              =              realm              .              createObject              <              Dog              >()              dog              .              name              =              "Fido"              dog              .              age              =              5              }                      

RealmModel interface

Instead of extending RealmObject, your classes can implement the RealmModel interface, adding the @RealmClass annotation:

                          @RealmClass              open              class              User              :              RealmModel              {              // ...              }                      

With this interface, all methods available on RealmObject become available through static methods. Note that a class that extends RealmObject does not need either the @RealmClass annotation or to implement RealmModel.

                          // With RealmObject              user              .              isValid              ();              user              .              addChangeListener              (              listener              );              // With RealmModel              RealmObject              .              isValid              (              user              );              RealmObject              .              addChangeListener              (              user              ,              listener              );                      

JSON

You can add a JSON object that maps to a RealmObject to Realm. The JSON object can be a String, a JSONObject or an InputStream. Realm will ignore any properties in the JSON not defined by the RealmObject. Add single objects through Realm.createObjectFromJson, and lists of objects through [Realm.createAllFromJson][api/io/realm/Realm.html#createAllFromJson-java.lang.Class-java.lang.String-).

                          // A RealmObject that represents a city              open              class              City              (              var              city              :              String              ?              =              null              var              id              :              Int              =              0              ):              RealmObject              ()              // Insert from a string              realm              .              executeTransaction              {              realm              ->              realm              .              createObjectFromJson              (              City              ::              class              .              java              ,              "{ city: \"Copenhagen\", id: 1 }"              )              }              // Insert multiple items using an InputStream              realm              .              executeTransaction              {              realm              ->              try              {              val              `is`              =              FileInputStream              (              File              (              "path_to_file"              ))              realm              .              createAllFromJson              (              City              ::              class              .              java              ,              `is`              )              }              catch              (              e              :              IOException              )              {              throw              RuntimeException              (              e              )              }              }                      

If a field in the JSON object is null and the field is required by the Realm model, Realm will throw an exception. If the field is optional, its value will be set to the field default when creating an object, and to null when updating an object. If the Realm model has a field that isn't present in the JSON object, the value will remain unchanged in the Realm model.

Adapters

Realm offers abstract utility classes to help bind data coming from OrderedRealmCollections (both RealmResults and RealmList implement this interface) to standard UI widgets.

  • Use RealmBaseAdapter with ListView. See an example.
  • Use RealmRecyclerViewAdapter with RecyclerView. See an example.

To use the adapters, add the dependencies to the application level build.gradle:

                          dependencies              {              compile              'io.realm:android-adapters:2.1.1'              }                      

Javadoc for the adapters can be found here and an example of their use can be found here.

Intents

Since RealmObjects are not Parcelable and cannot be passed directly, you must pass an identifier for the object you're working with. For example, if an object has a primary key, pass the primary key value in the Intent extras bundle:

                          // Assuming we had a person class with a @PrimaryKey on the 'id' field ...              val              intent              =              Intent              (              getActivity              (),              ReceivingService              ::              class              .              java              )              intent              .              putExtra              (              "person_id"              ,              person              .              getId              ())              myActivity              .              startService              (              intent              )                      

Retrieve the primary key value from the bundle on the receiving end (Activity, Service, IntentService, BroadcastReceiver, etc.), and then open a Realm and query for the RealmObject:

                          // in onCreate(), onHandleIntent(), etc.              val              personId              =              intent              .              getStringExtra              (              "person_id"              )              val              realm              =              Realm              .              getDefaultInstance              ()              try              {              val              person              =              realm              .              where              <              Person              >().              equalTo              (              "id"              ,              personId              ).              findFirst              ()              // do something with the person ...              }              finally              {              realm              .              close              ()              }                      

The overhead for re-opening the Realm on a different thread is very small.

You can find working examples in the Object Passing portion of the threading example. The example shows you how to pass id's and retrieve the RealmObject in common Android use cases.

Relationships

You can link any two RealmObjects together. Relationships are cheap in Realm: traversing links isn't expensive in terms of speed or memory. Let's explore the different types of relationships Realm lets you define between objects.

Many-to-one

To set up a many-to-one or one-to-one relationship, give a model a property whose type is one of your RealmObject subclasses:

                          open              class              Email              (              var              address              :              String              =              ""              ,              var              active              :              Boolean              =              false              ):              RealmObject              ()              open              class              Contact              (              var              name              :              String              =              ""              ,              var              email              :              Email              ?              =              null              ):              RealmObject              ()              realm              .              executeTransaction              {              val              bob              =              realm              .              createObject              <              Contact              >()              bob              .              name              =              "Bob Newhart"              ;              val              email1              =              realm              .              createObject              <              Email              >();              email1              .              address              =              "bob@example.com"              ;              bob              .              email              =              email1              ;              }                      

Each Contact has zero or one Email instances. Nothing would prevent you from using the same Email object with more than one Contact; the distinction between a many-to-one and a one-to-one relationship is up to your application.

Setting the relationship field to null will clear the reference:

This deletes the relationship between bob and email1, but email1 is still in the Realm.

Many-to-many

You can create a relationship to any number of objects from a single object via a RealmList<T> field declaration. Let's rewrite our example to support multiple email addresses:

                          open              class              Email              (              var              address              :              String              =              ""              ,              var              active              :              Boolean              =              false              ):              RealmObject              ()              open              class              Contact              (              var              name              :              String              =              ""              ,              var              emails              :              RealmList              <              Email              >              =              RealmList              ()              ):              RealmObject              ()                      

RealmLists are containers of RealmObjects; a RealmList behaves like a regular Kotlin List. You can use the same object in different RealmLists, and you can use this to model both one-to-many and many-to-many relationships.

                          realm              .              executeTransaction              {              val              contact              =              realm              .              createObject              <              Contact              >()              contact              .              name              =              "John Doe"              val              email1              =              realm              .              createObject              <              Email              >()              email1              .              address              =              "john@example.com"              email1              .              active              =              true              contact              .              emails              .              add              (              email1              )              val              email2              =              realm              .              createObject              <              Email              >()              email2              .              address              =              "jd@example.com"              email2              .              active              =              false              contact              .              emails              .              add              (              email2              )              }                      

It is possible to declare recursive relationships which can be useful when modeling certain types of data.

                          open              class              Person              (              var              name              :              String              =              ""              ,              var              friends              :              RealmList              <              Person              >              =              RealmList              ()              ):              RealmObject              ()                      

Setting the value to null for a RealmList field will clear the list. The list will be empty (length zero), but the objects that were in the list won't be deleted from the Realm. The getter for a RealmList will never return null: the returned object is always a list. The length might be zero.

Inverse relationships

Relationships are unidirectional. Take the two classes Person and Dog as an example:

                          open              class              Dog              (              var              name              :              String              =              ""              ,              var              age              :              Int              =              0              ):              RealmObject              ()              open              class              Person              (              @PrimaryKey              var              id              :              Long              ,              var              name              :              String              ,              var              dogs              :              RealmList              <              Dog              >              =              RealmList              ()              ):              RealmObject              ()                      

You can follow the link from a Person to a Dog, but there's no way to go from a Dog to its Person objects. You can resolve this by giving the Dog a @LinkingObjects annotation.

                          open              class              Dog              (              var              name              :              String              =              ""              ,              var              age              :              Int              =              0              ):              RealmObject              ()              {              // LinkingObjects must be final (i.e. `val`, not `var`)              @LinkingObjects              (              "dogs"              )              val              owners              :              RealmResults              <              Person              >?              =              null              }              open              class              Person              (              @PrimaryKey              var              id              :              Long              =              0              ,              var              name              :              String              =              ""              ,              var              dogs              :              RealmList              <              Dog              >              =              RealmList              ()              ):              RealmObject              ()                      

We've given Dog an owners field, and specified that it should contain all Person objects that have this Dog object in their dogs field.

The annotated field must be declared final, and must be of type RealmResults<T> where T is the type/class of opposite end of the relationship. Since relationships are either many-to-one or many-to-many, following inverse relationships could result in 0, 1 or more objects.

Like any other RealmResults set, you can query an inverse relationship.

Lists Of Primitives

Realm model classes can contains lists of primitive data types. This must be modeled using RealmList<T>, where T can be the following types: String, Integer, Boolean, Float, Double, Short, Long, Byte, ByteArray and Date.

                          open              class              Person              (              var              name              :              String              =              ""              ,              var              children              :              RealmList              <              String              >              =              RealmList              ()              ):              RealmObject              ()                      

Unlike lists of RealmModel's, lists of primitives can contain null values. If null values shouldn't be allowed, use the @Required annotation:

                          open              class              Person              (              var              name              :              String              =              ""              ,              @Required              var              children              :              RealmList              <              String              >              =              RealmList              ()              ):              RealmObject              ()                      

Lists of primitives do not support lists-of-lists and querying.

Before Realm Kotlin 4.0.0, it was common to model lists of primitives using a special Realm<String/Int> class. You can migrate from this approach to lists of primitives using the following migration code:

                          // Model classes              open              class              RealmString              (              var              value              :              String              =              ""              ,              ):              RealmObject              ()              open              class              Person              (              var              name              :              String              =              ""              ,              @Required              var              children              :              RealmList              <              String              >              =              RealmList              ()              ):              RealmObject              ()              // Migration code              val              objSchema              =              realmSchema              .              get              (              "Person"              )              objSchema              .              addRealmListField              (              "children_tmp"              ,              String              ::              class              .              java              )              .              setRequired              (              "children_tmp"              ,              true              )              .              transform              {              obj              ->              val              children              =              obj              .              getList              (              "children"              )              val              migratedChildren              =              obj              .              getList              (              "children_tmp"              ,              String              ::              class              .              java              )              for              (              child              in              children              )              {              migratedChildren              .              add              (              child              .              getString              (              "value"              ))              }              }              .              removeField              (              "children"              )              .              renameField              (              "children_tmp"              ,              "children"              )                      

Schemas

The default schema for a Realm is simply all the Realm model classes in a project. However, you can change this behavior—for instance, you might want to restrict a Realm to only contain a subset of classes. To do this, create a custom RealmModule.

                          // Create the module              @RealmModule              (              classes              =              [              Person              ::              class              ,              Dog              ::              class              ])              class              MyModule              // Set the module in the RealmConfiguration to allow only classes defined by the module.              val              config              =              RealmConfiguration              .              Builder              ()              .              modules              (              MyModule              ())              .              build              ()              // It is possible to combine multiple modules to one schema.              val              config2              =              RealmConfiguration              .              Builder              ()              .              modules              (              MyModule              (),              MyOtherModule              ())              .              build              ()                      

For library developers: Libraries that include Realm must expose and use their schema through a RealmModule. Doing so prevents the default RealmModule from being generated for the library project, which would conflict with the default RealmModule used by the app. The library's RealmModule is also how the library exposes its Realm classes to the app.

                          // A library must create a module and set library = true. This will              // prevent the default module from being created.              // allClasses = true can be used instead of listing all classes in the library.              @RealmModule              (              library              =              true              ,              allClasses              =              true              )              class              MyLibraryModule              // Library projects are therefore required to explicitly set their own module.              val              libraryConfig              =              RealmConfiguration              .              Builder              ()              .              name              (              "library.realm"              )              .              modules              (              MyLibraryModule              ())              .              build              ()              // Apps can add the library RealmModule to their own schema.              val              config              =              RealmConfiguration              .              Builder              ()              .              name              (              "app.realm"              )              .              modules              (              Realm              .              getDefaultModule              (),              MyLibraryModule              ())              .              build              ()                      

You can't have multiple RealmModule declarations in a single file. If you have two or more RealmModules, you will have to split the declarations into several files with exactly one declaration per file.

See a complete example of how RealmModules work between library and app projects here.

Writes

Unlike read operations, write operations in Realm must be wrapped in transactions. At the end of a write operation, you can either commit the transaction or cancel it. Committing a transaction writes all changes to disk (and if the Realm is synced, queues it for synchronization with Realm Object Server). If you cancel a write transaction, all the changes are discarded. Transactions are "all or nothing": either all the writes within a transaction succeed, or none of them take effect. This helps guarantee data consistency, as well as providing thread safety.

                          // Obtain a Realm instance              val              realm              =              Realm              .              getDefaultInstance              ()              realm              .              beginTransaction              ()              //... add or update objects here ...              realm              .              commitTransaction              ()                      

Or to discard the changes by canceling the transaction:

                          realm              .              beginTransaction              ()              val              user              =              realm              .              createObject              <              User              >()              //  ...              realm              .              cancelTransaction              ()                      

Write transactions block each other. This can cause ANR errors if you create write transactions on both the UI and background threads at the same time. To avoid this, use async transactions when creating write transactions on the UI thread.

If an exception happens inside a transaction, you'll lose the changes in that transaction, but the Realm itself won't be affected (or corrupted). If you catch the exception and the app continues, you'll need to cancel the transaction. If you use executeTransaction, this happens automatically.

Thanks to Realm's MVCC architecture, reads are not blocked while a write transaction is open. Unless you need to make simultaneous transactions from many threads at once, you can favor larger transactions that do more work over many fine-grained transactions. When you commit a write transaction to a Realm, all other instances of that Realm will be notified and be updated automatically.

Read & write access in Realm is ACID.

Creating objects

Wrap the createObject method in a write transaction.

                          realm              .              executeTransaction              {              val              user              =              realm              .              createObject              <              User              >()              // Create a new object              user              .              name              =              "John"              user              .              email              =              "john@corporation.com"              }                      

If you create an object instance first and use copyToRealm to add it to a Realm, you should wrap the copy action in a transaction, too. Realm supports as many custom constructors as you like as long as one of them is a public no-arguments constructor.

                          val              user              =              User              (              "John"              )              user              .              email              =              "john@corporation.com"              // Copy the object to Realm. Any further changes must happen on realmUser              realm              .              beginTransaction              ()              val              realmUser              =              realm              .              copyToRealm              (              user              )              realm              .              commitTransaction              ()                      

Remember, Realm only manages the returned object (realmUser in this example), not the object originally copied (user). To make changes to the object in the database, make changes to the returned copy, not the original.

If you are only interestered in inserting the object and not using the managed copy right away, it is possible to use insert instead. This works in a similar way to copyToRealm but is much faster as not returning the object makes it possible to optimize it more.

If you are inserting many objects, the recommend approach is to use insert or insertOrUpdate.

                          val              users              =              listOf              (              User              (              "John"              ),              User              (              "Jane"              ))              realm              .              beginTransaction              ()              realm              .              insert              (              users              )              realm              .              commitTransaction              ()                      

Transaction blocks

Instead of manually keeping track of beginTransaction, commitTransaction, and cancelTransaction, you can use the executeTransaction method, which will automatically handle begin/commit, and cancel if an error happens.

                          realm              .              executeTransaction              {              realm              ->              val              user              =              realm              .              createObject              (              User              ::              class              .              java              )              user              .              name              =              "John"              user              .              email              =              "john@corporation.com"              }                      

Asynchronous transactions

Since transactions are blocked by other transactions, you might want to write on a background thread to avoid blocking the UI thread. By using an asynchronous transaction, Realm will run that transaction on a background thread.

                          realm              .              executeTransactionAsync              ({              bgRealm              ->              val              user              =              bgRealm              .              createObject              <              User              >()              user              .              name              =              "John"              user              .              email              =              "john@corporation.com"              },              {              // Transaction was a success              },              {              error              ->              // Transaction failed and was automatically canceled              })                      

OnSuccess and OnError callbacks are both optional, but if provided, they will be called when the transaction succeeds or fails, respectively. Callbacks are controlled by the Looper, so they are only allowed on Looper threads.

                          val              transaction              =              realm              .              executeTransactionAsync              {              bgRealm              ->              val              user              =              bgRealm              .              createObject              <              User              >()              user              .              name              =              "John"              user              .              email              =              "john@corporation.com"              }                      

The RealmAsyncTask object can cancel any pending transaction if you need to quit the Activity/Fragment before the transaction is completed. Forgetting to cancel a transaction can crash the app if the callback updates the UI!

                          override              fun              onStop              ()              {              if              (              transaction              !=              null              &&              !              transaction              .              isCancelled              ())              {              transaction              .              cancel              ()              }              }                      

Updating strings and byte arrays

Since Realm operates on fields as a whole, it's not possible to directly update individual elements of strings or byte arrays. Instead, you'll need to read the whole field, make a modification to the individual element, and write it back again in a transaction block.

                          realm              .              executeTransaction              {              val              bytes              =              realmObject              .              binary              bytes              [              4              ]              =              'a'              realmObject              .              binary              =              bytes              }                      

Batch updates

If you need to update many objects at once, then the most efficient way is making a query that find the objects and use one of RealmResults.setX() methods, where X is the type of field you want to update.

                          realm              .              executeTransaction              {              val              persons              =              realm              .              where              <              Person              >().              equalTo              (              "invited"              ,              false              ).              findAll              ()              persons              .              setBoolean              (              "invited"              ,              true              )              }                      

It is also possible to use a generic set method called RealmResults.setValue(String fieldName, Object value), which automatically detects the type of input and converts it as appropriate. This is similar to how DynamicRealmObject.setX() and DynamicRealmObject.setValue() behave. Using RealmResults.setValue() is slower than using the specific typed method.

                          realm              .              executeTransaction              {              val              persons              =              realm              .              where              <              Person              >().              equalTo              (              "invited"              ,              false              ).              findAll              ()              persons              .              setValue              (              "invited"              ,              "true"              )              }                      

It is only possible to update fields directly on objects this way. Linked fields or list elements cannot be updated using these methods.

Queries

All fetches (including queries) are lazy in Realm, and the data is never copied.

Realm's query engine uses a Fluent interface to construct multi-clause queries.

                          open              class              Person              (              var              name              :              String              =              ""              ,              var              age              :              Int              =              0              ,              @Ignore              var              sessionId              :              Int              =              0              ):              RealmObject              ()                      

To find all users named John or Peter, you would write:

                          // Build the query looking at all users:              val              query              =              realm              .              where              <              User              >()              // Add query conditions:              query              .              equalTo              (              "name"              ,              "John"              )              query              .              or              ().              equalTo              (              "name"              ,              "Peter"              )              // Execute the query:              val              result1              =              query              .              findAll              ()              // Or alternatively do the same all at once (the "Fluent interface")              val              result2              =              realm              .              where              <              User              >()              .              equalTo              (              "name"              ,              "John"              )              .              or              ()              .              equalTo              (              "name"              ,              "Peter"              )              .              findAll              ()                      

This gives you a new instance of the class RealmResults, containing the users with the name John or Peter.

The method findAll executes the query; [RealmQuery][] includes a family of findAll methods:

  • findAll finds all objects that meet the query conditions
  • findAllAsync operates asynchronously on a background thread
  • findFirst (and findFirstAsync) find the first object that meets the query conditions

For full details, dive into the RealmQuery API reference.

Queries return a list of references to the matching objects, so you work directly with the original objects that matches your query. RealmResults inherits from AbstractList and behaves in similar ways. For example, RealmResults are ordered, and you can access the individual objects through an index. If a query has no matches, the returned RealmResults object will be a list of size(0) (not null).

If you wish to modify or delete objects in a RealmResults set, you must do so in a write transaction.

Note that you can also query relationships: read about link queries.

Filtering

The where method starts a RealmQuery by specifying a model. The filter criteria is specified with predicate methods, most of which have self-explanatory names (e.g., equalTo). A predicate always takes a field name as its first argument.

Not all predicates can be used with all field types; consult the [RealmQuery][] API reference for details.

For all data types, you have the following predicates:

  • equalTo
  • notEqualTo
  • anyOf

To match a field against a list of values, use anyOf. For example, to find the names "Jill," "William," or "Trillian", you can use anyOf("name", new String[]{"Jill", "William", "Trillian"}). The anyOf predicate is applicable to strings, binary data, and numeric fields (including dates).

Numeric data types, including Date, allow these additional predicates:

  • between (includes both end points, i.e., it is a bounded interval)
  • greaterThan
  • lessThan
  • greaterThanOrEqualTo
  • lessThanOrEqualTo

String fields allow these additional predicates:

  • contains
  • beginsWith
  • endsWith
  • like

All four string predicates have an optional third argument to control case sensitivity: Case.INSENSITIVE and Case.SENSITIVE. The default is Case.SENSITIVE.

The predicate like performs glob-style wildcard matching. The matching pattern consists of characters and one or more wildcards:

  • * matches 0 or more Unicode characters
  • ? matches a single Unicode character

For example, consider a Realm with four objects with a field called name which has the values William, Bill, Jill, and Trillian. The predicate like("name", "?ill*") will match the first three objects, and like("name", "*ia?") will match the first and the last object.

Binary data, strings, and lists of RealmObjects (RealmList) may be empty, i.e., have a length of zero. You can check for emptiness with:

  • isEmpty
  • isNotEmpty

If a field is not required, the value can have the value null (recall that fields which are RealmObjects can never be required, and the value can be null). You can check for null with:

  • isNull
  • isNotNull

Logical operators

Conditions are implicitly joined with logical and. Logical or joins must be applied explicitly using or.

                          open              class              User              (              var              name              :              String              =              ""              ,              var              age              :              Int              =              0              ,              @Ignore              var              sessionId              :              Int              =              0              ):              RealmObject              ()                      

You can also group conditions using beginGroup and endGroup to specify order of evaluation:

                          val              results              =              realm              .              where              <              User              >()              .              greaterThan              (              "age"              ,              10              )              // implicit AND              .              beginGroup              ()              .              equalTo              (              "name"              ,              "Peter"              )              .              or              ()              .              contains              (              "name"              ,              "Jo"              )              .              endGroup              ()              .              findAll              ()                      

Negate conditions with not. You can use the not operator with beginGroup/endGroup to negate sub-conditions only. If you wanted to all find users who are not named "Peter" or "Jo," the query could be:

                          val              results              =              realm              .              where              <              User              >()              .              not              ()              .              beginGroup              ()              .              equalTo              (              "name"              ,              "Peter"              )              .              or              ()              .              contains              (              "name"              ,              "Jo"              )              .              endGroup              ()              .              findAll              ()                      

With this particular query, though, it's easier to use anyOf:

                          val              results              =              realm              .              where              <              User              >()              .              not              ()              .              anyOf              (              "name"              ,              arrayOf              (              "Peter"              ,              "Jo"              ))              .              findAll              ()                      

Sorting

You can define how the results should be sorted when doing the query with the sort method.

                          var              result              =              realm              .              where              <              User              >().              sort              (              "age"              ).              findAll              ()                      

Or you can sort any results already retrieved by Realm:

                          result              =              result              .              sort              (              "age"              );              // Sort ascending              result              =              result              .              sort              (              "age"              ,              Sort              .              DESCENDING              );                      

Sorts are ascending by default; to change that, use Sort.DESCENDING as the second argument. It is possible to sort using multiple fields simultaneously.

Limiting Results

Most other database technologies provide the ability to 'paginate' results from queries (such as the 'LIMIT' keyword in SQLite). This is often done out of necessity to avoid reading too much from disk, or pulling too many results into memory at once.

Since queries in Realm are lazy, performing this sort of paginating is normally not needed when working with a local Realm file as Realm will only load objects from the results of the query once they are explicitly accessed.

However, there are a few cases where limiting results can be beneficial:

  • When using Query-based Realms, data will be fetched from the server when queried for. In this case it can make sense to limit the number of results as it directly impact how much data is transfered from the server.

  • When creating UI's that depend on a limited query result like a "Top 10 List". In this case, creating a limited query result will reduce the complexity of code needed to create such a screen.

In those cases, query results can be limited by applying the limit() keyword to the query.

                          val              people              =              realm              .              where              <              Person              >()              .              sort              (              "name"              )              .              limit              (              10              )              .              findAllAsync              ()                      

Limited query results are auto-updated like any other query results. This means that if 10 elements are returned when the query first returns, these 10 objects can be replaced or removed as the underlying data set changes.

When using fine-grained notifications, objects that stops being part of the RealmResults will be reported as deleted. This does not necessarily mean that they are deleted from the underlying Realm, just that they are no longer part of the query result.

The keywords distinct(), sort() and limit() will be applied in the order they are specified. Depending on the data set this can make a difference to the query result. Generally, limit() should be applied last.

Offsetting limited query results is not supported yet. This feature is being tracked in here.

Unique values

To return only unique values, use the distinct predicate. For example, to find out how many different names you have in your Realm:

                          val              unique              =              realm              .              where              (              Person              ::              class              .              java              ).              distinct              (              "name"              ).              findAll              ()                      

You can only call distinct on integer and string fields; other field types will throw an exception. As with sorting, you can specify multiple fields.

Chaining queries

You can run additional queries on result sets:

                          val              teenagers              =              realm              .              where              <              Person              >().              between              (              "age"              ,              13              ,              20              ).              findAll              ()              val              firstJohn              =              teenagers              .              where              ().              equalTo              (              "name"              ,              "John"              ).              findFirst              ()                      

You can also chain queries on child objects as well. Assume the above Person object has a list of Dog objects.

                          open              class              Dog              (              var              age              :              Int              =              0              ):              RealmObject              ()              open              class              Person              (              var              age              :              Int              =              0              ,              var              dogs              :              RealmList              <              Dog              >              =              RealmList              ()              ):              RealmObject              ()                      

You can query for all people between the age of 13 and 20 who have at least one dog which is one year old:

                          val              teensWithPups              =              realm              .              where              <              Person              >().              between              (              "age"              ,              13              ,              20              ).              equalTo              (              "dogs.age"              ,              1              .              toInt              ()).              findAll              ()                      

Note that query chains are built on RealmResults, not RealmQuery. When you add more conditions to a RealmQuery object, you are modifying the query itself.

It is possible to query links or relationships. Consider the model below:

                          open              class              Dog              (              var              id              :              String              =              ""              ,              var              name              :              String              =              ""              ,              var              color              :              String              =              ""              ):              RealmObject              ()              open              class              Person              (              var              id              :              String              =              ""              ,              var              name              :              String              =              ""              ,              var              dogs              :              RealmList              <              Dog              >              =              RealmList              ()              ):              RealmObject              ()                      

Each Person object has multiple dog relationships, as shown in this table diagram:

Table Diagram

Now, we can find specific people with link queries:

                          // persons => [U1,U2]              val              persons              =              realm              .              where              <              Person              >()              .              equalTo              (              "dogs.color"              ,              "Brown"              )              .              findAll              ()                      

The field name in equalTo is a path through the relationships, using a period (.) as the separator. The query above reads "find all Persons who have Dogs whose color is Brown." Note that the result will contain all Dog objects for Person objects that have at least one matching Dog:

                          persons              .              get              (              0              ).              dogs              // => [A,B]              persons              .              get              (              1              ).              dogs              // => [B,C,D]                      

Remember, we're searching for people who have particular kinds of dogs, not the actual dogs themselves.

Let's dig a little deeper:

                          // r1 => [U1,U2]              val              r1              =              realm              .              where              <              Person              >()              .              equalTo              (              "dogs.name"              ,              "Fluffy"              )              .              equalTo              (              "dogs.color"              ,              "Brown"              )              .              findAll              ()              // r2 => [U2]              val              r2              =              realm              .              where              <              Person              >()              .              equalTo              (              "dogs.name"              ,              "Fluffy"              )              .              findAll              ()              .              where              ()              .              equalTo              (              "dogs.color"              ,              "Brown"              )              .              findAll              ()              .              where              ()              .              equalTo              (              "dogs.color"              ,              "Yellow"              )              .              findAll              ()                      

The first query reads, "find all Persons who have dogs named 'Fluffy' and have dogs whose color is 'Brown.'" The second query reads, "find all Persons who have dogs named 'Fluffy.' Within that result set, find all Persons who have dogs whose color is 'Brown.' Then, within that result set, find all Persons who have dogs whose color is 'Yellow.'" So the first query finds two sets of Persons and returns the intersection of those sets; the second query operates differently, by taking the result set of each findAll and feeding it into the next where query to successively narrow down the results down. You could rewrite the second query by chaining:

                          val              set1              =              realm              .              where              <              Person              >().              equalTo              (              "dogs.name"              ,              "Fluffy"              ).              findAll              ()              val              set2              =              set1              .              where              ().              equalTo              (              "dogs.color"              ,              "Brown"              ).              findAll              ()              val              set3              =              set2              .              where              ().              equalTo              (              "dogs.color"              ,              "Yellow"              ).              findAll              ()                      

Using inverse relationships, you can expand your query possibilities. Let's consider the same two model classes, Person and Dog. Instead of starting the query with Person, you can query first for the dog, and follow the inverse relationship to the persons.

                          val              brownFluffies              =              realm              .              where              <              Dog              >()              .              equalTo              (              "color"              ,              "Brown"              )              .              equalTo              (              "name"              ,              "Fluffy"              )              .              findAll              ()              for              (              brownFluffy              in              brownFluffies              )              {              val              owners              =              brownFluffy              .              owners              // ...              }                      

You can also use link queries with inverse relationships:

                          val              dogs              =              realm              .              where              <              Dog              >().              equalTo              (              "persons.name"              ,              "Jane"              ).              findAll              ()                      

Auto-updating results

RealmResults are live, auto-updating views into the underlying data. If another thread, process or even device modifies an object in a RealmResults set, the change is instantly reflected. Your code doesn't need to re-run the query or manually refresh the data.

                          val              puppies              =              realm              .              where              <              Dog              >().              lessThan              (              "age"              ,              2              ).              findAll              ()              puppies              .              size              realm              .              executeTransaction              {              val              dog              =              realm              .              createObject              <              Dog              >()              dog              .              name              =              "Fido"              dog              .              age              =              1              }              puppies              .              addChangeListener              {              results              ->              // results and puppies point are both up to date              results              .              size              // => 1              puppies              .              size              // => 1              }                      

This applies to all RealmResults: all objects, filtered and chained.

This property of RealmResults not only keeps Realm fast and efficient, but it allows your code to be simpler and more reactive. For example, if your Activity or Fragment relies on the results of a query, you can just store the Realm object or RealmResults in a field. Its data will always be up-to-date when accessed.

Even though you don't have to refresh your RealmResults, your application may need to update its UI or run other tasks when data changes. You can subscribe to notifications when Realm data gets updated. Since results are auto-updating, it's important to not rely on indices and counts staying constant.

Aggregation

RealmResults offers aggregation convenience methods for operations like sums and averages across result sets.

                          val              results              =              realm              .              where              <              User              >().              findAll              ()              val              sum              =              results              .              sum              (              "age"              ).              toLong              ()              val              min              =              results              .              min              (              "age"              )              !!              .              toLong              ()              val              max              =              results              .              max              (              "age"              )              !!              .              toLong              ()              val              average              =              results              .              average              (              "age"              )              val              matches              =              results              .              size              .              toLong              ()                      

Iterations & snapshots

All Realm collections are live. This means that they always reflect the latest state. In most cases this is desirable, but what if you're iterating over a collection with the purpose of modifying the elements? For example:

                          val              guests              =              realm              .              where              <              Person              >()              .              equalTo              (              "invited"              ,              false              )              .              findAll              ()              realm              .              executeTransaction              {              for              (              i              in              guests              .              indices              )              {              // Index-based iteration for example              guests              [              i              ]              !!              .              invited              =              true              // ... use i for some other reason ...              }              }                      

Typically you would expect this simple loop to invite all guests. Because the RealmResults is updated immediately, though, only half the guests end up being invited! An invited guest is removed immediately from the collection, which will shift all elements. When the i parameter gets incremented, it will miss an element.

To prevent this, you can take a snapshot of a collection's data. A snapshot guarantees the order of elements will not change, even if an element is deleted or modified.

Iterators created from RealmResults will use a snapshot automatically, Iterators created from RealmList won't. To delete elements while iterating a RealmList, Iterator.remove() should be used instead of RealmList.remove() or other APIs which would remove elements from the RealmList indirectly to avoid ConcurrentModificationException. RealmResults and RealmList have a createSnapshot method to create one manually.

                          val              guests              =              realm              .              where              <              Person              >().              equalTo              (              "invited"              ,              false              ).              findAll              ()              // Use an iterator to invite all guests              realm              .              executeTransaction              {              for              (              guest              in              guests              )              {              guest              .              invited              =              true              }              }              // Use a snapshot to invite all guests              realm              .              executeTransaction              {              val              guestsSnapshot              =              guests              .              createSnapshot              ()              for              (              i              in              guestsSnapshot              .              indices              )              {              guestsSnapshot              [              i              ]              !!              .              invited              =              true              }              }                      

Deletion

You can delete the results of a query from the Realm:

                          // obtain the results of a query              val              results              =              realm              .              where              <              Dog              >().              findAll              ()              // All changes to data must happen in a transaction              realm              .              executeTransaction              {              realm              ->              // remove single match              results              .              deleteFirstFromRealm              ()              results              .              deleteLastFromRealm              ()              // remove a single object              val              dog              =              results              [              5              ]              dog              ?.              deleteFromRealm              ()              // Delete all matches              results              .              deleteAllFromRealm              ()              }                      

Asynchronous queries

Most queries in Realm are fast enough to run synchronously, even on the UI thread. However for either complex queries or queries on large data sets, it can be an advantage to run the query on a background thread.

                          val              result              =              realm              .              where              <              User              >()              .              equalTo              (              "name"              ,              "John"              )              .              or              ()              .              equalTo              (              "name"              ,              "Peter"              )              .              findAllAsync              ()                      

Note that the query is not blocking—it immediately returns a RealmResults<User>. This is a promise similar to the concept of a Future in standard Kotlin. The query will continue to run in a background thread, updating the returned instance of RealmResults once it's finished.

If you want to be notified when the query completes and the RealmResults object is updated, you can register a RealmChangeListener. This listener will be called every time the RealmResults are updated to reflect the latest changes in the Realm (usually after a commit).

                          val              callback              :              OrderedRealmCollectionChangeListener              <              RealmResults              <              User              >>              =              OrderedRealmCollectionChangeListener              {              results              ,              changeSet              ->              if              (              changeSet              ==              null              )              {              // The first time async returns with an null changeSet.              }              else              {              // Called on every update.              }              }              var              result              :              RealmResults              <              User              >?              =              null              override              fun              onStart              ()              {              super              .              onStart              ()              result              =              realm              .              where              <              User              >().              findAllAsync              ()              result              .              addChangeListener              {              results              ,              changeSet              ->              if              (              changeSet              ==              null              )              {              // The first time async returns with an null changeSet.              }              else              {              // Called on every update.              }              }              }                      

Remember to unregister any listeners when exiting an Activity or Fragment to avoid memory leaks.

                          public              override              fun              onStop              ()              {              super              .              onStop              ()              result              .              removeChangeListener              (              callback              )              // remove a particular listener              // or              result              .              removeAllChangeListeners              ()              // remove all registered listeners              }                      

Use isLoaded to check if a query has completed:

                          val              result              =              realm              .              where              <              User              >().              findAllAsync              ()              if              (              result              .              isLoaded              )              {              // Results are now available              }                      

Calling isLoaded on a RealmResults object obtained synchronously will always return true.

You can also wait until the query completes. This will block the thread, making the query synchronous again.

                          val              result              =              realm              .              where              <              User              >().              findAllAsync              ()              result              .              load              ()              // be careful, this will block the current thread until it returns                      

Note: You can only use asynchronous queries on a Looper thread. The asynchronous query needs to use the Realm's Handler in order to deliver results consistently. Trying to call an asynchronous query using a Realm opened inside a thread without a Looper will throw an IllegalStateException.

Migrations

When working with any database, it is likely your model classes (i.e. your database schema) will change over time. Since model classes in Realm are defined as standard objects, changing the schema is as easy as changing the interface of the corresponding RealmObject subclass.

Local migrations

For Realms that are not synced to the Realm Object Server, performing a migration requires two changes to your RealmConfiguration: setting a new schema version, and writing code to perform the migration.

                          val              config              =              RealmConfiguration              .              Builder              ()              .              schemaVersion              (              2              )              // Must be bumped when the schema changes              .              migration              (              MyMigration              ())              // Migration to run instead of throwing an exception              .              build              ()                      

Using this, the migration code will be run automatically if needed. We provide built-in methods so you can upgrade your schema on disk, and the data you stored for previous versions of the schema.

                          // Example migration adding a new class              class              MyMigration              :              RealmMigration              {              override              fun              migrate              (              realm              :              DynamicRealm              ,              oldVersion              :              Long              ,              newVersion              :              Long              )              {              var              oldVersion              =              oldVersion              // DynamicRealm exposes an editable schema              val              schema              =              realm              .              schema              // Migrate to version 1: Add a new class.              // Example:              // open class Person(              //     var name: String = "",              //     var age: Int = 0,              // ): RealmObject()              if              (              oldVersion              ==              0L              )              {              schema              .              create              (              "Person"              )              .              addField              (              "name"              ,              String              ::              class              .              java              )              .              addField              (              "age"              ,              Int              ::              class              .              javaPrimitiveType              )              oldVersion              ++              }              // Migrate to version 2: Add a primary key + object references              // Example:              // open class Person(              //     var name: String = "",              //     var age: Int = 0,              //     @PrimaryKey              //     var id: Int = 0,              //     var favoriteDog: Dog? = null,              //     var dogs: RealmList<Dog> = RealmList()              // ): RealmObject()              if              (              oldVersion              ==              1L              )              {              schema              .              get              (              "Person"              )              !!              .              addField              (              "id"              ,              Long              ::              class              .              javaPrimitiveType              ,              FieldAttribute              .              PRIMARY_KEY              )              .              addRealmObjectField              (              "favoriteDog"              ,              schema              .              get              (              "Dog"              ))              .              addRealmListField              (              "dogs"              ,              schema              .              get              (              "Dog"              ))              oldVersion              ++              }              }              }                      

See our migration sample app for more details.

If there is no file on disk when Realm launches, no migration is needed, and Realm will just create a new .realm file & schema based on the latest models defined in your code. This means that if you are in the middle of development and changing your schema frequently—and it's all right to lose all your data—you can delete your .realm file on disk instead of writing a migration. This can be helpful when tinkering with models early in the development cycle of your app.

                          val              config              =              RealmConfiguration              .              Builder              ()              .              deleteRealmIfMigrationNeeded              ()              .              build              ()                      

Notifications

It is possible to register a listener to receive notifications for changes on a Realm or its entities. Realm notifications are sent when the Realm as a whole is changed; collection notifications are sent when individual objects are changed, added, or removed.

Stop notification delivery by calling the removeChangeListener or removeAllChangeListeners method. Notifications will also stop if the object on which the listener is registered gets garbage collected, or if its Realm instance is closed. You should keep a strong reference of the object you're listening to as long as you need the notifications.

                          // Wrong way to register for notifications. Query result will              // be GC'ed when the method exits causing the listener to stop              // emitting notifications.              fun              runQuery              ()              {              realm              .              where              <              Person              >()              .              findAllAsync              ()              .              addChangeListener              {              persons              ->              // Persons was updated              }              }              // Right way to register for notifications. The listener will              // continue to emit notifications after the method exits.              var              persons              :              RealmResults              <              Person              >?              =              null              fun              runQuery              ()              {              persons              =              realm              .              where              <              Person              >()              .              findAllAsync              ()              persons              .              addChangeListener              {              persons              ->              // Persons was updated              }              }                      

Notifications are always delivered on the thread that they were originally registered on. That thread must have a running Looper. If the relevant write transaction happened on a different thread, the listener will be called asynchronously after the transaction is committed.

If the write transaction happened on the same thread, the listener will be called synchronously when the transaction is committed. However, in some cases the listener may be called when the transaction starts—if the Realm is advanced to the latest version, or Realm entities being observed were modified or deleted in a way that triggers notifications. In those cases, the listener runs within the context of the current write transaction, so an attempt to begin a new write transaction within the notification handler will throw an exception. You can use the Realm.isInTransaction method to determine if your code is executing within a write transaction.

Since asynchronous notifications are delivered through looper events, the delivery of notifications might be delayed by other events in the looper queue. When notifications can't be delivered immediately, changes from multiple write transactions may be coalesced into a single notification.

Realm notifications

Your UI or other looper threads can get notified of changes in a Realm by adding a listener, which is executed whenever the Realm is changed:

                          class              MyActivity              :              Activity              ()              {              lateinit              var              realm              :              Realm              lateinit              var              realmListener              :              RealmChangeListener              <              Realm              >              override              fun              onCreate              (              savedInstanceState              :              Bundle              ?)              {              super              .              onCreate              (              savedInstanceState              )              realm              =              Realm              .              getDefaultInstance              ()              realmListener              =              RealmChangeListener              {              // ... do something with the updates (UI, etc.) ...              }              realm              .              addChangeListener              (              realmListener              )              }              override              fun              onDestroy              ()              {              super              .              onDestroy              ()              // Remove the listener.              realm              .              removeChangeListener              (              realmListener              )              // Close the Realm instance.              realm              .              close              ()              }              }                      

A listener on a Realm receives the entire changed Realm.

Collection notifications

Collection notifications receive not the whole Realm, but instead fine-grained descriptions of changes. These consist of the indices of objects that have been added, removed, or modified since the last notification. Collection notifications are delivered asynchronously, first with the initial results and then again after each write transaction which changes any of the objects in the collection (or adds new ones).

These changes can be accessed via the OrderedCollectionChangeSet parameter that is passed to the change listener. This object holds information about the indices affected by deletions, insertions and changes.

The first two, deletions and insertions, record the indices of objects that have been added to or removed from the collection. This takes into account when you add objects to the Realm or delete them from the Realm. For RealmResults this also applies when you filter for specific values and the object was changed so that it is now matching the query or not matching anymore.

You're notified about changes whenever a field of an object has changed, which was previously part of the collection and is still part of it. This happens as well when to-one and to-many relationships change.

                          open              class              Dog              (              var              name              :              String              =              ""              ,              var              age              :              Int              =              0              ):              RealmObject              ()              open              class              Person              (              var              name              :              String              =              ""              ,              var              dogs              :              RealmList              <              Dog              >              =              RealmList              ()              ):              RealmObject              ()                      

Let's assume you're observing a list of dog owners as given by the model code above. You will be notified about modifications for a matched Person object for example when:

  • You modify the Person's name.
  • You add or remove a Dog from the list of dogs belonging to a Person.
  • You modify the age of a Dog belonging to that Person.

This makes it possible to discretely control animations and visual updates made to the content inside your UI, instead of arbitrarily reloading everything each time a notification occurs.

                          val              changeListener              =              OrderedRealmCollectionChangeListener              <              RealmResults              <              Person              >>              {              collection              ,              changeSet              ->              // `null`  means the async query returns the first time.              if              (              changeSet              ==              null              )              {              notifyDataSetChanged              ()              return              @OrderedRealmCollectionChangeListener              }              // For deletions, the adapter has to be notified in reverse order.              val              deletions              =              changeSet              .              deletionRanges              for              (              i              in              deletions              .              indices              .              reversed              ())              {              val              range              =              deletions              [              i              ]              notifyItemRangeRemoved              (              range              .              startIndex              ,              range              .              length              )              }              val              insertions              =              changeSet              .              insertionRanges              for              (              range              in              insertions              )              {              notifyItemRangeInserted              (              range              .              startIndex              ,              range              .              length              )              }              val              modifications              =              changeSet              .              changeRanges              for              (              range              in              modifications              )              {              notifyItemRangeChanged              (              range              .              startIndex              ,              range              .              length              )              }              }              }                      

The RealmRecyclerViewAdapter provides this out of the box.

Object notifications

Realm supports object-level notifications. You may register a notification on a particular RealmObject in order to be notified if the object is deleted, or whenever any of the managed fields on the object have their values modified.

Only managed RealmObjects can have listeners registered on them.

These changes can be accessed via the ObjectChangeSet parameter that is passed to the change listener. The ObjectChangeSet holds information about which fields were changed and if the RealmObject was deleted.

The ObjectChangeSet.isDeleted will return true if the object was deleted. After that the listener won't be called again.

The ObjectChangeSet.getChangedFields will return the names of changed fields if any of the object's managed fields were changed. You can also use ObjectChangeSet.isFieldChanged to test if a given field was just changed.

                          val              listener              =              object              :                            RealmObjectChangeListener              <              Dog              >              {              override              fun              onChange              (              dog              :              Dog              ,              changeSet              :              ObjectChangeSet              ?)              {              if              (              changeSet              ==              null              ||              changeSet              .              isDeleted              )              {              Log              .              i              (              "Tag"              ,              "The dog was deleted"              )              return              }              for              (              fieldName              in              changeSet              .              changedFields              )              {              Log              .              i              (              "Tag"              ,              "Field $fieldName was changed."              )              }              }              }                      

Notifications for the same value

Realm will treat all changes as something that will raise a notification. However, in many cases it is not desirable to refresh the UI if the value hasn't changed.

If you are updating single fields you can check the value in the Realm file before overridding it to avoid triggering notifications:

                          realm              .              executeTransaction              {              realm              ->              val              newName              =              "Jane"              val              managedPerson              =              getPerson              ()              if              (              newName              !=              managedPerson              .              name              )              {              managedPerson              .              name              =              newName              }              }                      

If you are inserting objects using Realm.copyToRealm() or Realm.copyToRealmOrUpdate() you can use an ImportFlag to indicate that only fields that actually changed should be updated:

                          realm              .              executeTransaction              {              realm              ->              fun              execute              (              realm              :              Realm              )              {              val              id              =              42              val              person              =              Person              (              id              ,              "Jane"              )              realm              .              copyToRealmOrUpdate              (              person              ,              ImportFlag              .              CHECK_SAME_VALUES_BEFORE_SET              )              }              }                      

This way notifications will only be raised for the fields that actually changed. When using this flag, null values in the input object are treated as a normal value like any other, so if the value in the Realm was non-null it will be overwritten with null and trigger a notification.

Encryption

Please take note of the Export Compliance section of our LICENSE, as it places restrictions against the usage of Realm if you are located in countries with an export restriction or embargo from the United States.

The Realm file can be encrypted on disk by passing a 512-bit encryption key (64 bytes) to the configuration using RealmConfiguration.Builder.encryptionKey:

                          val              key              =              ByteArray              (              64              )              SecureRandom              ().              nextBytes              (              key              )              val              config              =              RealmConfiguration              .              Builder              ()              .              encryptionKey              (              key              )              .              build              ()              val              realm              =              Realm              .              getInstance              (              config              )                      

Realm transparently encrypts and decrypts data with standard AES-256 encryption using the first 256 bits of the given 512-bit encryption key. Realm uses the other 256 bits of the 512-bit encryption key for the HMAC. You must supply the same encryption key every time you open that Realm. See examples/encryptionExample for an example of how to securely store keys between runs in the Android KeyStore so that other applications cannot read them.

Working with synced Realms

Threading

Realm makes it effortless to work with data on multiple threads without having to worry about consistency or performance, because objects and queries are auto-updating at all times. You can operate on live objects in different threads, reading and writing to them, without worrying about what other threads are doing to those same objects. If you need to change data, you can use a transaction. The other objects in the other thread will be updated in near real time (the updates will be scheduled as an event on the Looper, so Looper threads will be updated as soon as the event is processed).

The only limitation is that you cannot randomly pass Realm objects between threads. If you need the same data on another thread, you need to query for that data on the other thread. Furthermore, you can observe the changes using Realms reactive architecture. Remember, all objects are kept up to date between threads—Realm will notify you when the data changes.

Threading example

Assume we have an app that displays a list of customers. In a background thread (an Android IntentService) we poll a remote endpoint for new customers and then save them to Realm. When the background thread adds new customers, the data in the UI thread will be automatically updated. The UI thread gets notified via a RealmChangeListener and at that point we tell the UI widget to update itself. No need to re-query because Realm keeps everything up to date.

                          // in a Fragment or Activity, etc              // Listeners will only be triggered as long as the query result is              // not garbage collected, so keep a strong class reference to it.              private              var              customers              :              RealmResults              <              Customer              >?              =              null              override              fun              onCreate              (              savedInstanceState              :              Bundle              )              {              // ... boilerplate omitted for brevity              realm              =              Realm              .              getDefaultInstance              ()              // get all the customers              customers              =              realm              .              where              <              Customer              >().              findAllAsync              ()              !!              // ... build a list adapter and set it to the ListView/RecyclerView/etc              // set up a Realm change listener              val              changeListener              =              RealmChangeListener              <              RealmResults              <              Customer              >>              {              // This is called anytime the Realm database changes on any thread.              // Please note, change listeners only work on Looper threads.              // For non-looper threads, you manually have to use Realm.waitForChange() instead.              updateUi              ()              }              // Tell Realm to notify our listener when the customers results              // have changed (items added, removed, updated, anything of the sort).              customers              .              addChangeListener              (              changeListener              )              }              // In a background service, in another thread              inner              class              PollingService              :              IntentService              ()              {              public              override              fun              onHandleIntent              (              intent              :              Intent              ?)              {              val              realm              =              Realm              .              getDefaultInstance              ()              try              {              // go do some network calls/etc and get some data and stuff it into a 'json' var              val              json              =              customerApi              .              getCustomers              ()              realm              .              beginTransaction              ()              realm              .              createObjectFromJson              (              Customer              ::              class              .              java              ,              json              )              // Save a bunch of new Customer objects              realm              .              commitTransaction              ()              // At this point, the data in the UI thread is already up to date.              // ...              }              finally              {              realm              .              close              ()              }              }              // ...              }                      

Once the background service adds new customers to the Realm, the customers list is automatically updated in the UI without any additional intervention on your part. The same goes for individual objects. Suppose that you're only managing one object. Just change it on one thread and the UI thread automatically has the new data. If you need to respond to that change, just add a listener like we're doing above.

Using a Realm across threads

The only rule to using Realm across threads is to remember that Realm, RealmObject, and RealmResults instances cannot be passed across threads. Instead, use an asynchronous query or asynchronous transaction, to offload the operation to a background thread and bring any results back to the original thread for you.

When you want to access the same data from a different thread, you can obtain a new Realm instance (i.e. Realm.getInstance(RealmConfiguration config) or its cousins) and get your objects through a query.

The objects will map to the same data on disk, and will be readable and writeable from any thread.

Android framework threads

Be careful when working with these classes:

  • AsyncTask
  • IntentService

The AsyncTask class contains the doInBackground method which executes a background thread. The IntentService class contains the onHandleIntent(Intent intent) method which executes in a worker thread.

If you need to use Realm in either of these methods you should open the Realm, perform your work and then close the Realm before exiting. Below are a couple of examples.

AsyncTask

Open and close the Realm in the doInBackground method, as shown below.

                          private              class              DownloadOrders              :              AsyncTask              <              Void              ,              Void              ,              Int              >()              {              override              fun              doInBackground              (              vararg              voids              :              Void              ):              Int              {              // Now in a background thread.              // Open the Realm              val              realm              =              Realm              .              getDefaultInstance              ()              try              {              // Work with Realm              realm              .              createAllFromJson              (              Order              ::              class              .              java              ,              api              .              getNewOrders              ())              val              firstOrder              =              realm              .              where              <              Order              >().              findFirst              ()              return              firstOrder              .              id              }              finally              {              realm              .              close              ()              }              }              override              fun              onPostExecute              (              result              :              Int              ?)              {              // Back on the Android mainThread              // do something with orderId such as query Realm              // for the order and perform some operation with it.              }              }                      

IntentService

ChangeListeners will not work in an IntentService. Even though it is a Looper thread, each invocation of onHandleIntent is a separate event that doesn't "loop". This means that it is possible to register change listeners, but they will never be triggered.

Open and close the Realm in the onHandleIntent method, as shown below.

                          class              OrdersIntentService              (              name              :              String              )              :              IntentService              (              "OrdersIntentService"              )              {              override              fun              onHandleIntent              (              intent              :              Intent              ?)              {              // Now in a background thread.              // Open the Realm              val              realm              =              Realm              .              getDefaultInstance              ()              try              {              // Work with Realm              realm              .              createAllFromJson              (              Order              ::              class              .              java              ,              api              .              getNewOrders              ())              val              firstOrder              =              realm              .              where              <              Order              >().              findFirst              ()              val              orderId              =              firstOrder              .              id              }              finally              {              realm              .              close              ()              }              }              }                      

Multi-process support

Realm can be accessed from multiple processes with some limitations. Everything including the notifications should just work when accessing the same Realm from different processes in the same APK.

Freezing objects

While live-updating thread-confined Realm Objects works well in many cases, there are some cases where they do not, e.g. when Realm is part of an event-stream based architecture where objects might be read from multiple threads before ultimately being sent to the UI thread in a processed form. In those cases it can be beneficial to freeze a Realm, RealmResults, RealmList or Realm Object.

Freezing a Realm returns an immutable version that can be read and queried from any thread. All derived objects from a frozen Realm also become frozen.

                          Realm              liveRealm              =              Realm              .              getDefaultInstance              ();              Realm              frozenRealm              =              liveRealm              .              freeze              ();              new              Thread              (()              ->              {              RealmResults              <              Person              >              frozenPersons              =              frozenRealm              .              where              (              Person              .              class              ).              findAll              ();              frozenPersons              .              isFrozen              ();              // true              Person              frozenPerson              =              frozenPersons              .              first              ();              frozenPerson              .              isFrozen              ();              // true              }).              start              ();                      

The most common pattern is to attach a change listener to a live query result and then freeze the result before passing it on for further processing:

                          Realm              liveRealm              =              Realm              .              getDefaultInstance              ();              RealmResults              <              Person              >              liveResults              =              liveRealm              .              where              (              Person              .              class              ).              findAllAsync              ();              liveResults              .              addChangeListener              (              result              ->              {              doExpensiveWorkOnOtherThread              (              result              .              freeze              ());              });                      

It is not possible to start write transactions on frozen Realms, modify frozen objects or add change listeners to them. All of these methods will throw an IllegalStateException. To modify a frozen object, query for it on a live Realm and then modify it.

                          Realm              liveRealm              =              Realm              .              getDefaultInstance              ();              Person              frozenPerson              =              liveRealm              .              where              (              Person              .              class              ).              findFirst              ().              freeze              ();              frozenPerson              .              addChangeListener              (              listener              );              // Throws              new              Thread              (()              ->              {              Realm              bgLiveRealm              =              Realm              .              getDefaultInstance              ();              bgLiveRealm              .              beginTransaction              ();              frozenPerson              .              setName              (              "Jane"              );              // Throws              Person              bgLivePerson              =              bgLiveRealm              .              where              (              Person              .              class              ).              equalTo              (              "id"              ,              frozenPerson              .              getId              ()).              findFirst              ();              bgLivePerson              .              setName              (              "Jane"              );              bgLiveRealm              .              commitTransaction              ();              bgLiveRealm              .              close              ();              }).              start              ();                      

Once frozen, it is not possible to unfreeze an object. Use isFrozen() to query the state of an object. This method is thread-safe, even for otherwise thread-confined Realm objects.

                          Realm              liveRealm              =              Realm              .              getDefaultInstance              ();              Realm              frozenRealm              =              liveRealm              .              freeze              ();              liveRealm              .              isFrozen              ();              // false;              frozenRealm              .              isFrozen              ();              // true              new              Thread              (()              ->              {              liveRealm              .              isFrozen              ();              // false;              frozenRealm              .              isFrozen              ();              // true              }).              start              ();                      

Frozen objects are available as long as the live Realm that spawned them stays open. Care must be taken not to close the live Realm until all threads are done with the frozen objects. It is possible to close frozen Realms before the live Realm is closed.

                          Realm              liveRealm              =              Realm              .              getDefaultInstance              ();              Realm              frozenRealm              =              liveRealm              .              freeze              ();              Person              frozenPerson              =              frozenRealm              .              where              (              Person              .              class              ).              findFirst              ();              frozenPerson              .              isValid              ();              // true              // Closing the live Realm, also closes the frozen data              liveRealm              .              close              ();              frozenPerson              .              isValid              ();              // false                      

Be aware that caching too many frozen objects can have negative impact on file size. See here for more info.

Other libraries

This section describes how you can integrate Realm with other commonly used libraries for Android.

GSON

GSON is a library created by Google for deserializing and serializing JSON. GSON should work with Realm out of the box.

                          // Using the User class              open              class              User              (              var              name              :              String              =              ""              ,              var              email              :              String              =              ""              ,              ):              RealmObject              ()              var              gson              =              GsonBuilder              ().              create              ()              var              json              =              "{ name : 'John', email : 'john@corporation.com' }"              var              user              =              gson              .              fromJson              (              json              ,              User              ::              class              .              java              )                      

You can also see an example of how GSON can work with Realm in our GridViewExample.

Serialization

For full compatibility with libraries like Retrofit you will often want to be able to both deserialize and serialize an object. Serializing Realm objects to JSON does not work with GSON's default behavior as GSON will use field values instead of getters and setters.

To make GSON serialization work with Realm you will need to write a custom JsonSerializer for each object that can be serialized and register it as a TypeAdapter.

This Gist shows how it can be done.

Primitive lists

Although Realm support import arrays in JSON to lists Of primitives natively, lack of query support of primitive list may still be a problem. You may want to import the JSON arrays of primitive types as a list of RealmObject. If it is not possible to change the JSON API, you can write a custom TypeAdapter for GSON that automatically maps between the primitive type from JSON and the wrapper object used by Realm.

In this Gist is an example of using a wrapper object for Integers, but the template can be used for all primitive arrays with datatypes supported by Realm.

Troubleshooting

Realm objects can contain fields that internally contain circular references. When this happens GSON can throw a StackOverflowError. We have seen this happen when a Realm object has a Drawable field:

                          open              class              Person              (              @Ignore              internal              var              avatar              :              Drawable              ?              =              null              // other fields, etc              ):              RealmObject              ()                      

The Person class above contains an Android Drawable that has the @Ignore annotation applied. During GSON serialization the Drawable was being inspected and caused a StackOverflowError (GitHub Issue). To alleviate this, add the following code to your shouldSkipField method.

                          fun              shouldSkipField              (              f              :              FieldAttributes              ):              Boolean              {              return              f              .              getDeclaringClass              ().              equals              (              RealmObject              ::              class              .              java              )              ||              f              .              getDeclaringClass              ().              equals              (              Drawable              ::              class              .              java              )              }                      

Please note the Drawable.class evaluation. This tells GSON to skip this field during serialization. Adding this will alleviate the StackOverflowError.

Parceler

Parceler is a library that automatically generates the boilerplate required to make an object respect the Parcelable interface. Due to Realm's use of proxy classes, Parceler requires the following setup to work with Realm's model classes.

Proxy classes in Realm uses the fully qualified name of the model class plus the RealmProxy suffix, so for example io.realm.model.Person becomes io_realm_model_PersonRealmProxy.class

                          // All classes that extend RealmObject will have a matching RealmProxy class created              // by the annotation processor. Parceler must be made aware of this class. Note that              // the class is not available until the project has been compiled at least once.              @Parcel              (              implementations              =              {              some_package_PersonRealmProxy              .              class              },     value =                            Parcel              .              Serialization              .              BEAN              ,              analyze              =              {              Person              .              class              }) class                            Person              (              // ...              ):              RealmObject              ()                      

If you are using Gradle for getting Parceler, please make sure the following lines are there (see here for more details):

                          compile              "org.parceler:parceler-api:1.0.3"              apt              "org.parceler:parceler:1.0.3"                      

There are some important restrictions to be aware of when using Parceler:

  1. If your model contains a RealmList you need to register a special adapter.
  2. Once an object has been parceled, it becomes detached from Realm and at this point behaves like an unmanaged object containing a snapshot of the data. Further changes to this object will not be persisted in Realm.

Retrofit

Retrofit is a library from Square that makes it easy to work with a REST API in a typesafe manner.

Realm will work with both Retrofit 1.* and 2.* out of the box, but note that Retrofit does not automatically add objects to Realm, instead you must manually add them using the realm.copyToRealm or realm.copyToRealmOrUpdate methods.

                          val              service              =              restAdapter              .              create              (              GitHubService              ::              class              .              java              )              val              repos              =              service              .              listRepos              (              "octocat"              )              // Copy elements from Retrofit to Realm to persist them.              realm              .              executeTransaction              {              realm              ->              val              realmRepos              =              realm              .              copyToRealmOrUpdate              (              repos              )              // ...              }                      

Robolectric

Robolectric is a library that allows you to run JUnit tests directly in the JVM instead of in a phone or emulator. Currently, Robolectrics does not support native libraries like those that are bundled with Realm. This means that for now it is not possible to test Realm using Robolectric.

You can follow the feature request here: https://github.com/robolectric/robolectric/issues/1389

RxJava

RxJava is a Reactive Extensions library from Netflix that extends the Observer pattern. It makes it possible to observe changes to data as composable sequences.

Realm has first-class support for RxJava 2 Flowable and Observable

  • Realm
  • RealmResults
  • RealmList
  • RealmObject
  • DynamicRealm
  • DynamicRealmObject
  • RealmResults changesets
  • RealmList changesets
  • RealmObject changesets
  • DynamicRealmObject changesets
                          // Combining Realm, Retrofit and RxJava              // Load all persons and merge them with their latest stats from GitHub (if they have any)              realm              =              Realm              .              getDefaultInstance              ()              val              api              =              retrofit              .              create              (              GitHubService              ::              class              .              java              )              realm              .              where              <              Person              >().              isNotNull              (              "username"              ).              findAllAsync              ()              .              asFlowable              ()              .              filter              {              it              .              isLoaded              }              .              flatMap              {              Observable              .              from              (              it              )              }              .              flatMap              {              api              .              user              (              it              .              getGithubUserName              ())              }              .              observeOn              (              AndroidSchedulers              .              mainThread              ())              .              subscribe              {              showUser              (              it              )              }                      

Asynchronous Queries are non-blocking—the code above will immediately return a RealmResults instance. If you want to ensure you're only operating on a loaded list, filter the Flowable via the filter operator and check the list by calling the [RealmResults.isLoaded](api/io/realm/RealmResults.html#isLoaded--) method. By checking to see if the `RealmResults` are loaded you can then determine if your query has completed or not.

All Realm Observables and Flowables return frozen objects. This means that these objects are immutable, but can be read and queried from any thread or Scheduler without fear of running into IllegalStateException: Realm access from incorrect thread..

See the RxJava sample project for more examples.

RxJava is an optional dependency, which means that Realm doesn't automatically include it. This has the benefit that you can choose which version of RxJava to use as well as avoid the method count bloat in projects that does not use RxJava. RxJava has to be manually added to the build.gradle file.

                          dependencies              {              compile              'io.reactivex:rxjava:2.1.4'              }                      

It is possible to configure how Realm create streams by creating a custom RxObservableFactory. This is configured using RealmConfiguration.

                          val              config              =              RealmConfiguration              .              Builder              ()              .              rxFactory              (              MyRxFactory              ())              .              build              ()                      

If no RxObservableFactory is defined, Realm defaults to RealmObservableFactory which is a class provided by Realm that supports RxJava <= 2.*. Since Realm version 7.0.0, this class can be configured to return live or frozen objects. The default is frozen objects.

                          // Disable frozen objects for Observables              RealmConfiguration              config              =              new              RealmConfiguration              .              Builder              ()              .              rxFactory              (              new              RealmObservableFactory              (              false              ))              .              build              ()                      

If you are using RxJava 1 you can use this library by David Karnok to convert between RxJava 2 and RxJava 1 types.

Testing and debugging

See our unitTestExample for information on how Realm can be combined with JUnit3, JUnit4, Robolectric, Mockito and PowerMock.

Android Studio debugging

There's a small "gotcha" to be aware of when working using Android Studio or IntelliJ: the debugger can provide misleading values depending on the debugging view you're using.

For example, adding a watch in Android Studio on a RealmObject will display values of the fields. Unfortunately, these values are wrong because the field values are not used. Realm creates a proxy object behind the scenes and overrides the getters and setters in order to access the persisted data in the Realm. Adding a watch for any of the accessors will yield the correct values. See the image below: Android Studio, IntelliJ Debug RealmObject

In the image above, the debugger has stopped on line 113. There are three watch values, the person variable and the person.getName and person.getAge accessors. The code from lines 107 to 111 alters the person instance by changing the name and age. These values are then persisted in a transaction. On line 113, where the debugger is currently paused, the person watch instance is reporting on field values and they are incorrect. The watch values that use the accessor for person.getName and person.getAge report values that are correct.

Please note, the .toString method will output the correct values, but the watch panel will not (when watching a variable which is a RealmObject).

NDK debugging

Realm is a library that contains native code. We recommend that you use a crash reporting tool, such as Crashlytics, to track native errors so we are in a better position to help you if something goes wrong.

Debugging NDK crashes is usually cumbersome as the default stack trace provides minimal information that can be of use. Crashlytics will allow you to capture valuable NDK crash information. To enable NDK crash reporting in Crashlytics, please follow the steps outlined in this guide.

To enable NDK crash reporting for your project, add this to the root of your build.gradle file. Please note, the values androidNdkOut and androidNdkLibsOut are not needed.

                          crashlytics              {              enableNdk              true              }                      

Current limitations

Realm generally tries to have as few constraints as possible, and we are continuously adding new features based on feedback from the community. However, Realm still has a few limitations. Please refer to our GitHub issues for a more comprehensive list of known issues.

Models

Realm models have no support for final (val) and volatile fields. This is mainly to avoid discrepancies between how an object would behave as managed by Realm or unmanaged.

Realm model classes are not allowed to extend any other object than RealmObject. If declared, the default constructor (constructor with no parameters) must always be empty. The reason is that a default contructor will call methods which assume a Realm instance is present. But that instance isn't create before the contructor returns. You can add other constructors for your convenience.

General

Realm aims to strike a balance between flexibility and performance. In order to accomplish this goal, realistic limits are imposed on various aspects of storing information in a Realm. For example:

  1. The upper limit of class names is 57 characters. Realm Kotlin prepends class_ to all names, and the browser will show it as part of the name.
  2. The length of field names has a upper limit of 63 character.
  3. It is not possible to have two model classes with the same name in different packages.
  4. Nested transactions are not supported, and an exception is thrown if they are detected.
  5. Strings and byte arrays (byte[]) cannot be larger than 16 MB.
  6. Realm models have no support for final and volatile fields. This is mainly to avoid discrepancies between how an object would behave as managed by Realm or unmanaged.
  7. If a custom constructor is provided, a public no-arg constructor must also be present.
  8. Realm model classes are not allowed to extend any other class than RealmObject.

To avoid size limitations and a performance impact, it is best not to store large blobs (such as image and video files) directly in Realm. Instead, save the file to a file store (such as S3) and keep only the location of the file and any relevant metadata in Realm.

Sorting and querying on strings

Sorting and case-insensitive string matches in queries are only supported for character sets in Latin Basic, Latin Supplement, Latin Extended A, and Latin Extended B (UTF-8 range 0–591). Also, setting the case insensitive flag in queries when using equalTo, notEqualTo, contains, endsWith, beginsWith, or like will only work on characters from the English locale.

Realm uses non-standard sorting for upper and lowercase letters, sorting them together rather than sorting uppercase first. That means that '- !"#0&()*,./:;?_+<=>123aAbBcC...xXyYzZ is the actual sorting order in Realm. Read more about these limitations here.

Threads

Although Realm files can be accessed by multiple threads concurrently, you cannot hand over Realms, Realm objects, queries, and results between threads. The thread example shows how to use Realm in a multithreading environment. Read more about Realm's threading.

Although Realm files can be accessed by multiple threads concurrently, they can only be accessed by a single process at a time. Different processes should either copy Realm files or create their own.

RealmObject's hashCode

A RealmObject is a live object, and it might be updated by changes from other threads. Although two Realm objects returning true for RealmObject.equals must have the same value for RealmObject.hashCode, the value is not stable, and should neither be used as a key in HashMap nor saved in a HashSet.

Multi-process

  • Accessing encrypted Realms from different processes simultaneously is not supported. There is a Realm Core issue (#1845) tracking this.
  • Accessing the same Realms from different processes in different APKs is not supported. It is safe to do it but things like notifications won't work as expected.
  • Accessing synced Realms from different processes is not supported.

Incremental builds

Realms bytecode transformer supports incremental builds, but in a few cases a full build is required. The transformer is not able to detect these cases by itself.

  • Adding or removing the @Ignore annotation from a field in a model class.
  • Adding or removing the static keyword from a field in a model class.
  • Adding or removing the transient keyword from a field in a model class.

Failing to perform a full build in these cases will either crash the app or cause fields to return the default value for the datatype (e.g. 0 or null) instead of returning the true value stored in Realm.

Best practices

Out of the box, Realm works seamlessly with Android. The main thing that you have to keep in mind is that RealmObjects are thread confined. The importance of understanding this comes into play more when you want to start passing Realm objects between activities, to background services, broadcast receivers and more.

Preventing "Application Not Responding" (ANR) errors

Typically Realm is fast enough to read and write data on Android's main thread. However, write transactions are blocking across threads so in order to prevent accidental ANR's we advise that you perform all Realm write operations on a background thread (not Android's main thread). Learn how to perform operations on the background thread via Realms Asynchronous Transactions.

Controlling the lifecycle of Realm instances

Choosing the proper lifecycle for a Realm instance is a balancing act. Because RealmObjects and RealmResults are accessed through a lazy cache, keeping a Realm instance open for as long as possible not only avoids the overhead incurred in opening and closing it but is likely to allow queries against it to run more quickly. On the other hand, an open Realm instance holds significant resources, some of which are not controlled by the Kotlin memory manager. Kotlin cannot automatically administer these resources. It is essential that code that opens a Realm instance closes it when it is no longer needed.

Realm uses an internal reference counted cache so that, after getting the first Realm instance, getting subsequent instances on the same thread is free. The underlying resources are released, though, only when all of the instances on that thread are closed.

One reasonable choice is to make the lifecycle of the Realm instance congruent with the lifecycles of views that observe it. The examples below demonstrate this using a Fragment and an Activity, each with a RecyclerView that displays data retrieved from a Realm instance. In both examples the Realm instance and the RecyclerView Adapter are initialized in the create method and closed in the corresponding destroy method. Note that this is safe, even for the Activity: the database will be left in a consistent state even if the onDestroy and close methods are never called.

Clearly, if most of the Fragments associated with an Activity require access to the same dataset, it would make sense for the Activity, not the individual Fragments, to control the lifecycle of the instance.

                          // Setup Realm in your Application              class              MyApplication              :              Application              ()              {              override              fun              onCreate              ()              {              super              .              onCreate              ()              Realm              .              init              (              this              )              val              realmConfiguration              =              RealmConfiguration              .              Builder              ().              build              ()              Realm              .              setDefaultConfiguration              (              realmConfiguration              )              }              }              // onCreate()/onDestroy() overlap when switching between activities.              // Activity2.onCreate() will be called before Activity1.onDestroy()              // so the call to getDefaultInstance in Activity2 will be fast.              class              MyActivity              :              Activity              ()              {              private              lateinit              var              realm              :              Realm              private              var              recyclerView              :              RecyclerView              ?              =              null              override              fun              onCreate              (              savedInstanceState              :              Bundle              ?)              {              super              .              onCreate              (              savedInstanceState              )              realm              =              Realm              .              getDefaultInstance              ()              setContentView              (              R              .              layout              .              activity_main              )              recyclerView              =              findViewById              (              R              .              id              .              recycler_view              )              as              RecyclerView              recyclerView              !!              .              setAdapter              (              MyRecyclerViewAdapter              (              this              ,              realm              .              where              <              MyModel              >().              findAllAsync              ())              )              // ...              }              override              fun              onDestroy              ()              {              super              .              onDestroy              ()              realm              .              close              ()              }              }              // Use onCreateView()/onDestroyView() for Fragments.              // Note that if the db is large, getting the Realm instance may, briefly, block rendering.              // In that case it may be preferable to manage the Realm instance and RecyclerView from              // onStart/onStop instead. Returning a view, immediately, from onCreateView allows the              // fragment frame to be rendered while the instance is initialized and the view loaded.              class              MyFragment              :              Fragment              ()              {              private              lateinit              var              realm              :              Realm              private              var              recyclerView              :              RecyclerView              ?              =              null              override              fun              onCreateView              (              inflater              :              LayoutInflater              ,              container              :              ViewGroup              ?,              savedInstanceState              :              Bundle              ?              ):              View              ?              {              realm              =              Realm              .              getDefaultInstance              ()              val              root              =              inflater              .              inflate              (              R              .              layout              .              fragment_view              ,              container              ,              false              )              recyclerView              =              root              .              findViewById              (              R              .              id              .              recycler_view              )              as              RecyclerView              recyclerView              !!              .              setAdapter              (              MyRecyclerViewAdapter              (              getActivity              (),              realm              .              where              <              MyModel              >().              findAllAsync              ())              )              // ...              return              root              }              override              fun              onDestroyView              ()              {              super              .              onDestroyView              ()              realm              .              close              ()              }              }                      

Reuse RealmResults and RealmObjects

On the UI thread and all other Looper threads, all RealmObjects and RealmResults are automatically refreshed when changes are made to the Realm. This means that it isn't necessary to fetch those objects again when reacting to a RealmChangeListener. The objects are already updated and ready to be redrawn on the screen.

                          class              MyActivity              :              Activity              ()              {              private              lateinit              var              realm              :              Realm              private              val              allPersons              :              RealmResults              <              Person              >?              =              null              private              val              realmListener              =              RealmChangeListener              <              Realm              >              {              realm              ->              // Just redraw the views. `allPersons` already contain the              // latest data.              invalidateView              ()              }              override              fun              onCreate              (              savedInstanceState              :              Bundle              ?)              {              super              .              onCreate              (              savedInstanceState              )              realm              =              Realm              .              getDefaultInstance              ()              realm              .              addChangeListener              (              realmListener              )              allPersons              =              realm              .              where              <              Person              >().              findAll              ()              // Create the "live" query result              setupViews              ()              // Initial setup of views              invalidateView              ()              // Redraw views with data              }              // ...              }                      

Autoincrementing IDs

Autoincrementing IDs are not supported by Realm by design. This is primarily because it is impossible to generate such keys in a distributed environment, and compatibility between data stored in a local Realm and a synchronized Realm is a high priority. Note that Realm does not need primary keys in order to create relationships.

It is still possible to efficiently create primary keys with Realm that satisfy the use cases provided by autoincrementing IDs, but it is important to identify what the autoincrementing ID is used for:

1) To provide a unique identifier in order to identify the object. This can be replaced by a GUID, which guarantees uniqueness and can be created by a device even when it's offline:

                          open              class              Person              (              @PrimaryKey              var              id              :              String              =              UUID              .              randomUUID              ().              toString              (),              var              name              :              String              =              ""              ):              RealmObject              ()                      

2) To provide loose insertion order. An example is sorting tweets. This can be replaced by a createdAt field, which doesn't need to be a primary key:

                          open              class              Person              (              @PrimaryKey              var              id              :              String              =              UUID              .              randomUUID              ().              toString              (),              var              createdAt              :              Date              =              Date              (),              var              name              :              String              =              ""              ):              RealmObject              ()                      

3) To provide strict insertion order. An example is a list of tasks. This can be modelled using a RealmList which will guarantee insertion order, even if devices have been offline.

                          open              class              Person              (              var              name              :              String              =              ""              ):              RealmObject              ()              open              class              SortedPeople              (              @PrimaryKey              var              id              :              Int              =              0              ,              var              persons              :              RealmList              <              Person              >              =              RealmList              ()              ):              RealmObject              ()              // ...              // Create wrapper object when creating object              val              config              =              RealmConfiguration              .              Builder              ()              .              initialData              {              realm              ->              realm              .              insert              (              SortedPeople              ())              }              // Insert objects through the wrapper              realm              .              executeTransaction              (              Realm              .              Transaction              {              realm              ->              val              sortedPeople              =              realm              .              where              (              SortedPeople              ::              class              .              java              ).              findFirst              ()              sortedPeople              !!              .              persons              .              add              (              Person              ())              })                      

If you have a use case where you still think autoincrementing IDs will be a better fit, you can use this helper class, but note that keys generated using this class are not usable if you:

1) Create Realm Objects in multiple processes. 2) Want to share the Realm between multiple devices at some point in the future.

For autoincrementing IDs that are safe to create across processes, you will need to query for the max value each time you begin a transaction:

                          realm              .              executeTransaction              {              realm              ->              val              maxValue              =              realm              .              where              <              MyObject              >().              max              (              "primaryKeyField"              )              var              pk              =              0              if              (              maxValue              !=              null              )              {              pk              =              maxValue              .              toInt              ()              +              1              }              realm              .              createObject              <              MyObject              >(              pk              ++)              realm              .              createObject              <              MyObject              >(              pk              ++)              }                      

Examples

Take a look at our examples to see Realm used in practice in an app. See here for more details on how to run the examples.

The introExample contains simple examples of how you use the Realm API.

The gridViewExample is a trivial app that shows how to use Realm as the backing store for a GridView. It also shows how you could populate the database with JSON using GSON plus how to use ABI splits to minimize the size of the final APK.

The threadExample is a simple app that shows how to use Realm in a multithreaded environment.

The adapterExample shows how to use the RealmBaseAdapter and RealmRecyclerViewAdapter to make Realm work with Android ListView and RecyclerView in an elegant way.

The jsonExample demonstrates Realm's JSON facilities.

The encryptionExample shows you how to work with encrypted Realms.

The rxJavaExamples shows how Realm works together with RxJava.

The unitTestExample shows how you can write unit tests when working with Realm.

The multiProcessExample shows how to use Realm from different processes in the same APK.

Recipes

We've put together some recipes showing how to use Realm to accomplish a few specific tasks. We add more recipes regularly, so check back often. If there's an example you'd like to see, please open an issue on GitHub.

  • Building an Android Clustered Map View
  • Building an Android Search Controller
  • Building a Grid Layout With RecyclerView and Realm

FAQ

How can I find and view the content of my Realm file(s)?

This SO question describes where to find your Realm file. You can then view the content with our Realm Studio.

How big is the Realm Base library?

Once your app is built for release and split for distribution, Realm should only add about 800KB to your APK in most cases. The releases we distribute are significantly larger because they include support for more architectures (ARM7, ARMv7, ARM64, x86, MIPS). The APK file contains all supported architectures but the Android installer will only install native code for the device's architecture. As a consequence, the installed app is smaller than the size of the APK file.

It is possible to reduce the size of the Android APK itself by splitting the APK into a version for each architecture. Use the Android Build Tool ABI Split support by adding the following to your build.gradle:

                          android              {              splits              {              abi              {              enable              true              reset              ()              include              'armeabi-v7a'              ,              'arm64-v8a'              ,              'x86'              ,              'x86_64'              }              }              }                      

Select the architectures that you'd like to include and a separate APK will be built for each. See the Android Tools documentation about ABI Splits for more information.

An example is also included on GitHub.

If you don't want to handle multiple APK's it is also possible to restrict the number of architectures supported in a single APK. This is done by adding abiFilters to your build.gradle:

                          android              {              defaultConfig              {              ndk              {              abiFilters              'armeabi-v7a'              ,              'arm64-v8a'              ,              'mips'              ,              'x86'              ,              'x86_64'              }              }              }                      

For more details about ABI splits and filters, read this article by Brijesh Masrani.

Is Realm open source?

Yes! Realm's internal C++ storage engine and the language SDKs over it are entirely open source and licensed under Apache 2.0. Realm also optionally includes a closed-source Realm Platform Extensions component, but that is not required to use Realm as an embedded database.

What is the difference between a normal Kotlin object and a Realm object?

The main difference is that a normal Kotlin object contains its own data while a Realm object doesn't contain data but get or set the properties directly in the database.

Instances of Realm objects can be either managed or unmanaged.

  • Managed objects are persisted in Realm, are always up to date and thread confined. They are generally more lightweight than the unmanaged version as they take up less space on the KotlinJava heap.
  • Unmanaged objects are just like ordinary Kotlin objects, they are not persisted and they will not be updated automatically. They can be moved freely across threads.

It is possible to convert between the two states using Realm.copyToRealm and Realm.copyFromRealm.

Why do model classes need to extend RealmObject?

We need to add Realm specific functionality to your model classes. It also allows us to use generics in our APIs, making it easier to read and use. If you don't want to extend a base class you can instead implement the RealmModel interface.

What are the RealmProxy classes about?

The RealmProxy classes are our way of making sure that the Realm object doesn't contain any data itself, but instead access the data directly in the database.

For every model class in your project, the Realm annotation processor will generate a corresponding RealmProxy class. This class extends your model class and is what is returned when you call Realm.createObject(), but from the point of view of your code you won't notice any difference.

Why do I need to use transactions when writing Realm objects?

Transactions are needed to ensure multiple fields are updated as one atomic operation. It allows you to define the scope of the updates that must be either fully completed or not completed at all (in case of errors or controlled rollback). By specifying the scope of the transaction you can control how frequent (or fast) your updates are persisted (i.e. insert multiple objects in one operation).

When doing inserts in a normal SQL based database like SQLite you are inserting multiple fields at once. This is automatically wrapped in a transaction, but is normally not visible to the user. In Realm these transactions are always explicit.

How do I handle out-of-memory exceptions?

Realm for Android is built upon an embedded storage engine. The storage engine does not allocate memory on the JVM heap but in native memory. When the storage engine cannot allocate native memory or the file system is full, Realm will throw an java.lang.OutOfMemoryError exception. It is important to not ignore this error. If your app continues running, accessing the Realm file might leave it in a corrupted or an inconsistent state. It is safest to terminate the app.

Large Realm file size

You should expect a Realm database to take less space on disk than an equivalent SQLite database, but in order to give you a consistent view of your data, Realm operates on multiple versions of a Realm. This can cause the Realm file to grow disproportionately if the difference between the oldest and newest version of data grows too big.

How much space these versions take up depends on the amount of changes in each transaction. Many small transactions have the same overhead as fewer larger ones.

If you suspect you have too many versions live at the same time, you can enable maxNumberOfActiveVersions() on the RealmConfiguration. This will cause Realm to throw an IllegalStateException if you try to create versions above the desired number. This is useful to catch undesirable patterns.

                          RealmConfiguration              config              =              new              RealmConfiguration              .              Builder              ()              .              maxNumberOfActiveVersions              (              64              )              .              build              ();              Realm              realm              =              Realm              .              getInstance              (              config              );              // This will throw if it would exceed the number of versions held on to by Realm              realm              .              beginTransaction              ();                      

Realm will automatically remove the older versions of data if they are not being used anymore, but the actual file size will not decrease. The extra space will be reused by future writes.

If needed, the extra space can be removed by compacting the Realm file. This can either be done manually or automatically when opening the Realm for the first time.

Unexpected file size growth usually happens for one of three reasons:

1) You open a Realm on a background thread and forget to close it again.

This will cause Realm to retain a reference to the data on the background thread and is the most common cause for Realm file size issues. The solution is to make sure to correctly close your Realm instance. Read more here and here. Realm will detect if you forgot to close a Realm instance correctly and print a warning in Logcat. Threads with loopers, like the UI thread, do not have this problem.

2) You are holding references to too many versions of frozen objects.

Unexpected file size growth may occur if you are freezing objects and keep references to them for a longer period. If you truly need to cache a large number of versions, consider if it is possible to use Realm.copyFromRealm() instead to only copy the data you need.

3) You read some data from a Realm and then block the thread on a long-running operation while writing many times to the Realm on other threads.

This will cause Realm to create many intermediate versions that needs to be tracked. Avoiding this scenario is a bit more tricky, but can usually be done by either either batching the writes or avoiding having the Realm open while otherwise blocking the background thread.

I see a network call to Mixpanel when I run my app

Realm collects anonymous analytics when you run the Realm bytecode transformer on your source code. This is completely anonymous and helps us improve the product by flagging which version of Realm you use and what OS you use, and what we can deprecate support for. This call does not run when your app is running on your user's devices — only when your source code is compiled. You can see exactly how & what we collect, as well as the rationale for it in our source code.

Couldn't load "librealm-jni.so"

If your app uses other native libraries that don't ship with support for 64-bit architectures, Android will fail to load Realm's librealm-jni.so file on ARM64 devices. This is because Android cannot load 32-bit and 64-bit native libraries concurrently. The best solution would be to have all libraries provide the same set of supported ABIs, but sometimes that may not be doable if you are using a 3rd-party library. See VLC and Realm Library conflicts.

The workaround to this issue is to exclude Realm's ARM64 library from the APK file by adding the following code to the app's build.gradle. You can refer to Mixing 32- and 64-bit Dependencies in Android for more information.

                          android              {              //...              packagingOptions              {              exclude              "lib/arm64-v8a/librealm-jni.so"              }              //...              }                      

Also, there is a bug with Android Gradle Plugin 1.4.0 betas that leads it to improperly pack .so files included in jar files (see Realm Java issue 1421). To solve this problem, you can revert to Android Gradle Plugin 1.3.0 or use Android Gradle Plugin 1.5.0+.

We are aware of a number of 3rd party libraries, frameworks and management apps which do not have 64-bit support yet:

  • Parallel Space—but you can advice your users to install the 64 bit version instead.
  • RenderScript—NDK r14 will probably support 64 bit.
  • Unity3d.

How do I backup and restore Realms?

Realms are stored in files on the file system. By calling the getPath you can get the full path of a Realm file. If you plan to back up or restore a Realm file this way, all instances of the Realm should be closed.

It is also possible to backup an open Realm file using realm.writeCopyTo.

If you want to backup a file to an external location like Google Drive. You can read this tutorial: part 1, part 2, and part 3.

Blackberry devices

Some Blackberry devices are capable of running Android apps. Unfortunately, the provided runtime environment is not complete, and we cannot guarantee compatibility. Known error messages include:

            io.realm.exceptions.RealmFileException: Function not implemented in io_realm_internal_SharedRealm.cpp line 81 Kind: ACCESS_ERROR.          

If you see issues with Blackberry devices, please consider to contribute a fix since both Realm Core and Realm Kotlin are open source projects.

How to store and retrieve the encryption key used by Realm

Using Android KeyStore is probably the most secure way to store the Realm's encryption key. Here is a recommended way to use it.

  1. Using Android's KeyStore, generate an asymmetric RSA key, that will be stored/retrieved securely by Android. On version >= M the system requires user PIN (or finger print) to unlock the KeyStore, so even on rooted devices you have an extra layer of security.
  2. Generate a symmetric key (AES), that will be used to encrypt the Realm.
  3. Encrypt the symmetric AES key using your private RSA key.
  4. Now it's safe to store the encrypted AES key on filesystem (in a SharedPreferences for example).
  5. When you need to use your encrypted Realm, retrieve your encrypted AES key, decrypt it using the public RSA key, then use it in the RealmConfiguration to open the encrypted Realm.

For an end-to-end example, look at our demo repositories:

  • https://github.com/realm/realm-android-user-store
  • https://github.com/realm/realm-java/tree/feature/example/store_password/examples/StoreEncryptionPassword (using the fingerprint API)

How to use Realm in system apps on custom ROMs

Realm uses named pipes in order to support notifications and access to the Realm file from multiple processes. While this is allowed by default for normal user apps, it is disallowed for system apps.

System apps are defined by setting setting android:sharedUserId="android.uid.system" in the Android manifest and if you are creating such an app you risk seeing a security violation in Logcat that looks something like this:

            05-24 14:08:08.984  6921  6921 W .realmsystemapp: type=1400 audit(0.0:99): avc: denied { write } for name="realm.testapp.com.realmsystemapp-Bfqpnjj4mUvxWtfMcOXBCA==" dev="vdc" ino=14660 scontext=u:r:system_app:s0 tcontext=u:object_r:apk_data_file:s0 tclass=dir permissive=0 05-24 14:08:08.984  6921  6921 W .realmsystemapp: type=1400 audit(0.0:100): avc: denied { write } for name="realm.testapp.com.realmsystemapp-Bfqpnjj4mUvxWtfMcOXBCA==" dev="vdc" ino=14660 scontext=u:r:system_app:s0 tcontext=u:object_r:apk_data_file:s0 tclass=dir permissive=0          

In order to fix this you need to adjust the SELinux security rules in the ROM. This can be done by using the tool audit2allow which is a tool that ships as part of AOSP.

1) First pull the current policy from the device adb pull /sys/fs/selinux/policy. 2) Copy the SELinux error inside a text file called input.txt. 3) Run the audit2allow tool: audit2allow -p policy -i input.txt. 4) The tool should output a rule you can add to your existing policy that allow you to use Realm.

An example on how such a policy can look like is provided below:

            # Allow system_app to create named pipes required by Realm # Credit: https://github.com/mikalackis/platform_vendor_ariel/blob/master_oreo/sepolicy/system_app.te allow system_app fuse:fifo_file create; allow system_app system_app_data_file:fifo_file create; allow system_app system_app_data_file:fifo_file { read write }; allow system_app system_app_data_file:fifo_file open;          

audit2allow is produced when compiling AOSP/ROM and only runs on Linux. You can read more about it here. Also note that since Android Oreo, Google changed the way it configures SELinux and the default security policies are now much more modularized. Read more about that here.

How do I customize dependecies defined by the Realm Gradle plugin?

Realm uses a Gradle plugin because it makes it easier to setup a larger number of dependencies, but it unfortunately also makes it a bit harder to customize, e.g. if you want to ignore some transitive dependencies.

If you want to customize Realm beyond what is exposed by the plugin, you can manually setup all the dependencies and ignore the Gradle plugin. How to do this for Kotlin projects is shown below:

Standard approach when using the gradle plugin:

                          buildscript              {              ext              .              kotlin_version              =              '1.2.41'              repositories              {              jcenter              ()              mavenCentral              ()              }              dependencies              {              classpath              "io.realm:realm-gradle-plugin:7.0.0-beta"              classpath              "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"              }              }              apply              plugin:              'com.android.application'              apply              plugin:              'kotlin-android'              apply              plugin:              'kotlin-kapt'              apply              plugin:              'realm-android'                      

Manual setup:

                          buildscript              {              ext              .              kotlin_version              =              '1.2.41'              ext              .              realm_version              =              '7.0.0-beta'              repositories              {              jcenter              ()              mavenCentral              ()              }              dependencies              {              classpath              "io.realm:realm-transformer:$realm_version"              classpath              "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"              }              }              apply              plugin:              'com.android.application'              apply              plugin:              'kotlin-android'              apply              plugin:              'kotlin-kapt'              import              io.realm.transformer.RealmTransformer              android              .              registerTransform              (              new              RealmTransformer              (              project              ))              dependencies              {              api              "io.realm:realm-annotations:$realm_version"              api              "io.realm:realm-android-library:$realm_version"              api              "io.realm:realm-android-kotlin-extensions:$realm_version"              kapt              "io.realm:realm-annotations-processor:$realm_version"              }                      

If you are using the Realm Object Server, realm-android-kotlin-extensions and realm-android-library needs to be suffixed with -object-server so they become: realm-android-kotlin-extensions-object-server and realm-android-library-object-server.

How do I debug from a Virtual Machine?

Chrome debugger tries to connect to the realm server running on port 8083.

You must send the 8083 port to the 8083 port of the host machine.

socat tcp-listen:8083,bind=localhost,reuseaddr,fork tcp:<VM address>.1:8083

You then need to redirect to `localhost:8083`.

socat tcp-listen:8083,bind=<VM address>,reuseaddr,fork tcp:localhost:8083

In order to reach the android port you may need to redirect localhost:8083 to android's port. This should happen if you run npm run android which automatically runs adb forward tcp:8083 tcp:8083. This will make localhost:8083 arrive at android's 8083 port where the Realm server is running.

Permission denied when opening a Realm on Huawei devices

This error usually looks something like this:

                          io              .              realm              .              exceptions              .              RealmError              :              Unrecoverable              error              .              Permission              denied              in              /              Users              /              Nabil              /              Dev              /              realm              /              realm              -              java              /              realm              /              realm              -              library              /              src              /              main              /              cpp              /              io_realm_internal_SharedRealm              .              cpp              line              101              at              io              .              realm              .              internal              .              SharedRealm              .              nativeGetSharedRealm              (              SharedRealm              .              java              )              at              io              .              realm              .              internal              .              SharedRealm              .<              init              >(              SharedRealm              .              java              :              172              )              at              io              .              realm              .              internal              .              SharedRealm              .<              init              >(              SharedRealm              .              java              :              172              )              at              io              .              realm              .              internal              .              SharedRealm              .              getInstance              (              SharedRealm              .              java              :              219              )              at              io              .              realm              .              internal              .              SharedRealm              .              getInstance              (              SharedRealm              .              java              :              209              )              at              io              .              realm              .              RealmCache              .              doCreateRealmOrGetFromCache              (              RealmCache              .              java              :              319              )              at              io              .              realm              .              RealmCache              .              createRealmOrGetFromCache              (              RealmCache              .              java              :              282              )              at              io              .              realm              .              Realm              .              getInstance              (              Realm              .              java              :              353              )                      

This error can manifest itself after an app upgrade or factory reset. The root cause is described here.

In short, the management files used by Realm to coordinate interprocess access and notifications no longer have the same user uid as the rest of the app which means that Realm no longer is able to read these files.

From Realm Kotlin 5.15.0 these management files are created with more permissive access rights. Specifically they are granted 0666 as opposed to 0600 before 5.15.0. This means that the app process, regardless of the owner uid, can now read these files. This has no practical security implications as the app is already running inside its own sandbox.

Unfortunately these management files are only created the first time the Realm is opened, so if an app using Realm 5.15.0 encounters this error, it means the Realm was created using an older version of Realm.

In order to re-create the management files, you can use one of the following solutions three solutions:

A) Delete the Realm and recreate it:

                          val              config              =              Realm              .              getDefaultConfiguration              ()              var              realm              :              Realm              try              {              realm              =              Realm              .              getInstance              (              config              )              }              catch              (              e              :              RealmError              )              {              if              (              e              .              message              .              contains              (              "Permission denied"              ))              {              Realm              .              deleteRealm              (              config              )              realm              =              Realm              .              getInstance              (              config              )              }              else              {              throw              e              }              }                      

All local data will be lost.

B) Rename the Realm file:

                          val              config              =              RealmConfiguration              .              Builder              ()              .              name              (              "default.realm"              )              .              build              ()              var              realm              :              Realm              try              {              realm              =              Realm              .              getInstance              (              config              )              }              catch              (              e              :              RealmError              )              {              if              (              e              .              message              .              contains              (              "Permission denied"              ))              {              val              oldRealm              =              File              (              config              .              path              )              val              newConfig              =              RealmConfiguration              .              Builder              ()              .              name              (              "default-new.realm"              )              .              build              ()              val              newRealm              =              File              (              newConfig              .              path              )              check              (              oldRealm              .              renameTo              (              newRealm              ))              {              "Failed to rename Realm"              }              Realm              .              deleteRealm              (              config              )              realm              =              Realm              .              getInstance              (              newConfig              )              }              else              {              throw              e              }              }                      

Doing this while the Realm is open can result in some changes not being copied.

C) Manually delete the management files:

                          val              config              =              RealmConfiguration              .              Builder              ()              .              name              (              "default.realm"              )              .              build              ()              var              realm              :              Realm              try              {              realm              =              Realm              .              getInstance              (              config              )              }              catch              (              e              :              RealmError              )              {              if              (              e              .              message              .              contains              (              "Permission denied"              ))              {              val              oldRealm              =              File              (              config              .              path              )              val              newConfig              =              RealmConfiguration              .              Builder              ()              .              name              (              "default-new.realm"              )              .              build              ()              val              newRealm              =              File              (              newConfig              .              path              )              check              (              oldRealm              .              renameTo              (              newRealm              ))              {              "Failed to rename Realm"              }              Realm              .              deleteRealm              (              config              )              realm              =              Realm              .              getInstance              (              newConfig              )              }              else              {              throw              e              }              }                      

Doing this while the Realm file is open can corrupt the file.

Getting help

  • Need help with your code? Ask on StackOverflow. We actively monitor & answer questions on SO!
  • Have a bug to report? Open an issue on our repo. If possible, include the version of Realm, a full log, the Realm file, and a project that shows the issue.
  • Have a feature request? Open an issue on our repo. Tell us what the feature should do, and why you want the feature.
  • Love to follow what comes up next? Look at our changelog. The log shows the latest additions and changes we plan to release soon, and the history of how Realm has evolved.
  • Getting started
    • Prerequisites
    • Installation
    • Important Notes on Realm for Kotlin
      • Samples
    • Browse the Realm database
      • Realm Studio
      • Stetho Realm
    • Initializing Realm
  • Realms
    • Opening Realms
      • Configuring a Realm
      • The default Realm
    • Opening a synchronized Realm
    • Read-only Realms
    • In-memory Realms
    • Dynamic Realms
    • Closing Realms
    • Auto-Refresh
  • Models
    • Field types
    • Required fields
    • Primary keys
    • Indexing properties
    • Ignoring properties
    • Counters
    • Overriding property names
  • Working with RealmObjects
    • Auto-updating objects
    • Customizing objects
    • RealmModel interface
    • JSON
    • Adapters
    • Intents
  • Relationships
    • Many-to-one
    • Many-to-many
    • Inverse relationships
    • Lists Of Primitives
  • Schemas
  • Writes
    • Creating objects
    • Transaction blocks
    • Asynchronous transactions
    • Updating strings and byte arrays
    • Batch updates
  • Queries
    • Filtering
    • Logical operators
    • Sorting
    • Limiting Results
    • Unique values
    • Chaining queries
    • Link queries
    • Auto-updating results
    • Aggregation
    • Iterations & snapshots
    • Deletion
    • Asynchronous queries
  • Migrations
    • Local migrations
  • Notifications
    • Realm notifications
    • Collection notifications
    • Object notifications
    • Notifications for the same value
  • Encryption
  • Working with synced Realms
  • Threading
    • Threading example
    • Using a Realm across threads
    • Android framework threads
      • AsyncTask
      • IntentService
    • Multi-process support
    • Freezing objects
  • Other libraries
    • GSON
      • Serialization
      • Primitive lists
      • Troubleshooting
    • Parceler
    • Retrofit
    • Robolectric
    • RxJava
  • Testing and debugging
    • Android Studio debugging
    • NDK debugging
  • Current limitations
    • Models
    • General
    • Sorting and querying on strings
    • Threads
    • RealmObject's hashCode
    • Multi-process
    • Incremental builds
  • Best practices
    • Preventing "Application Not Responding" (ANR) errors
    • Controlling the lifecycle of Realm instances
    • Reuse RealmResults and RealmObjects
    • Autoincrementing IDs
  • Examples
  • Recipes
  • FAQ
    • How can I find and view the content of my Realm file(s)?
    • How big is the Realm Base library?
    • Is Realm open source?
    • What is the difference between a normal Kotlin object and a Realm object?
    • Why do model classes need to extend RealmObject?
    • What are the RealmProxy classes about?
    • Why do I need to use transactions when writing Realm objects?
    • How do I handle out-of-memory exceptions?
    • Large Realm file size
    • I see a network call to Mixpanel when I run my app
    • Couldn't load "librealm-jni.so"
    • How do I backup and restore Realms?
    • Blackberry devices
    • How to store and retrieve the encryption key used by Realm
    • How to use Realm in system apps on custom ROMs
    • How do I customize dependecies defined by the Realm Gradle plugin?
    • How do I debug from a Virtual Machine?
    • Permission denied when opening a Realm on Huawei devices
  • Getting help

Error Writing File, Is Your Harddrive Almost Full? (Getdirectory)

Source: https://docs.mongodb.com/realm-legacy/docs/kotlin/latest/index.html

Posted by: mckinnongreaboy.blogspot.com

0 Response to "Error Writing File, Is Your Harddrive Almost Full? (Getdirectory)"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel