This is not the current version. View the latest documentation

Getting started

Download Realm for Android or see the source for realm-java on GitHub.

Prerequisites

  • We do not support Java outside of Android at the moment.
  • Android Studio >= 0.8.6 — to use Realm from Eclipse, see below.
  • A recent version of the Android SDK.
  • JDK version >=7.
  • We support all Android versions since API Level 9 (Android 2.3 Gingerbread & above).

Installation

You can either use Maven or manually add a Jar to your project.

Maven

  1. Make sure your project uses jcenter as a dependency repository (default on latest version of the Android Gradle plugin)
  2. Add compile 'io.realm:realm-android:0.84.0' to the dependencies of your project
  3. In the Android Studio menu: Tools->Android->Sync Project with Gradle Files

Jar

  1. Download the release package and unzip.
  2. Create a new project with Android Studio
  3. Copy the realm-VERSION.jar folder into app/libs
  4. In the Android Studio menu: Tools->Android->Sync Project with Gradle Files
  1. Download the release package and unzip.
  2. Copy the jar file and folders (containing the librealm-jni.so files) from distribution/eclipse/ to your app’s libs folder.
  3. Right click on the realm jar file from libs folder, and go to “Build Path” -> “Add to Build path”.
  4. Right click your project and select “Properties”, go to “Java Compiler” -> “Annotation Processing”, check “Enable project specific settings” and then click “Apply”.
  5. Continue to “Annotation Processing” -> “Factory Path” and check “Enable project specific settings”. “Click Add JARs” and select the realm jar file in “libs”, click OK, Apply and finally build.
  6. In order to trigger the annotation processor, you must add the annotation @RealmClass before every one of your RealmObject subclasses.

ProGuard

Realm generates a proxy class for each RealmObject at compile time. To ensure that these classes can be found after running an obfuscation and static analysis tool like ProGuard add the configuration below to your ProGuard configuration file. Your Realm version needs to be higher than 0.81.1.

-keep class io.realm.annotations.RealmModule
-keep @io.realm.annotations.RealmModule class *
-keep class io.realm.exceptions.* { *; }
-keep class io.realm.internal.async.BadVersionException { *; }
-keep class io.realm.internal.OutOfMemoryError { *; }
-keep class io.realm.internal.TableSpec { *; }
-keep class io.realm.internal.ColumnType { *; }
-dontwarn javax.**
-dontwarn io.realm.**

Realm Browser

The Realm Browser is only available on Mac OS X at the moment.
We are working on Windows & Linux versions.

We also provide a standalone Mac app named Realm Browser to read and edit .realm databases.

Realm Browser

You can generate a test database with sample data using the menu item Tools > Generate demo database.

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

The Realm Browser is available on the Mac App Store. If you’ve already updated to Realm Java 0.83, there is a compatible pre-release version of the Browser on the Realm Browser GitHub page.

API Reference

You can consult our full API reference for all classes, methods & more.

Examples

The root folder contains a few examples to get you started. You just Import Project in Android Studio and hit run.

The RealmIntroExample in the root folder contains simple examples of how you use the current API. Checkout the source code, as you will only see little output in the Log.

The RealmGridViewExample 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.

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

The RealmAdapterExample shows how to use the RealmBaseAdapter to bind RealmResults to Android lists in a convenient way.

The RealmJsonExample illustrates how to use the new Realm JSON facilities.

The RealmEncryptionExample shows you how to work with encrypted Realms.

Getting Help

Models

Realm data models are defined by implementing something very similar to a traditional Java Bean. Simply extend our RealmObject class and let the Realm annotations processor generate proxy classes.

public class User extends RealmObject {

    @PrimaryKey
    private String          name;
    private int             age;

    @Ignore
    private int             sessionId;

    // Standard getters & setters generated by your IDE…
    public String getName() { return name; }
    public void   setName(String name) { this.name = name; }
    public int    getAge() { return age; }
    public void   setAge(int age) { this.age = age; }
    public int    getSessionId() { return sessionId; }
    public void   setSessionId(int sessionId) { this.sessionId = sessionId; }
}

Be aware that the getters and setters will be overridden by the generated proxy class used in the back by RealmObjects, so any custom logic you add to the getters & setters will not actually be executed.

Field types

Realm supports the following field types: boolean, byte, short, int, long, float, double, String, Date and byte[]. The integer types byte, short, int, and long are all mapped to the same type (long actually) within Realm. Moreover, subclasses of RealmObject and RealmList<? extends RealmObject> are supported to model relationships.

The boxed types Boolean, Byte, Short, Integer, Long, Float and Double can also be used in model classes. Using these types, it is possible to set the value of a field to null.

Required fields and null values

In some cases, null is not an appropriate value of a field. The @Required annotation can be used to tell Realm to enforce checks to disallow null values. You don’t have to add @Required to fields of primitive types as these cannot be null.

Ignoring properties

The annotation @Ignore implies that a field should not be persisted to disk. Ignored fields are useful if your input contains more fields than your model, and you don’t wish to have many special cases for handling these unused data fields.

Indexing properties

The annotation @Index will add a search index to the field. This will make inserts slower and the data file larger but queries will be faster. So it’s recommended to only add index when optimizing specific situations for read performance. We support indexing: String, byte, short, int, long, boolean and Date fields.

Primary keys

To promote a field to primary key, you use the annotation @PrimaryKey, and the field type has to be either string or integer (short, int or long). It is not possible to use multiple fields (compound key) as a primary key. Using a string field as a primary key implies that the field is indexed (the annotation @PrimaryKey implicitly sets the annotation @Index).

Using primary keys makes it possible to use the createOrUpdate() method, which will look for an existing object with this primary key, and update it if one is found; if none is found, it will create a new object instead.

Using primary keys has an effect on the performance. Creating and updating object will be a little slower while querying is expected to be a bit faster. It is hard to give numbers as the changes in performance depend on the size of your dataset.

When calling Realm.createObject(), it will return a new object with all fields set to the default value. In this case, there might be a conflict with an existing object whose primary key field is the default value. To avoid this, it is suggested to create a standalone object, set values of the fields, and then copy it to Realm by copyToRealm() method.

MyObject obj = new MyObject();
obj.setId(42);
obj.setName("Fish");
realm.beginTransaction();
// This will create a new one in Realm
// realm.copyToRealm(obj);
// This will update a existing one with the same id or create a new one instead
realm.copyToRealmOrUpdate(obj);
realm.commitTransaction();

Primary keys cannot have the value null, and the @PrimaryKey annotation has the @Required annotation implicitly.

Limitations

Due to how the proxy classes override getters and setters in the model classes there are some restrictions to what is allowed in a model class.

Writes

Read operations are implicit which means that objects can be accessed and queried at any time. All write operations (adding, modifying, and removing objects) must be wrapped in write transactions. A write transaction can either be committed or cancelled. During the commit, all changes will be written to disk, and the commit will only succeed if all changes can be persisted. By cancelling a write transaction, all changes will be discarded. Using write transactions, your data will always be in a consistent state.

Write transactions are also used to ensure thread safety:

// Obtain a Realm instance
Realm realm = Realm.getInstance(this);

realm.beginTransaction();

//... add or update objects here ...

realm.commitTransaction();

While working with your RealmObjects inside a write transaction, you might end up in a situation where you wish to discard the change. Instead of committing it, and then reverting it, you can simply cancel the write transaction:

realm.beginTransaction();
User user = realm.createObject(User.class);

//  ... 

realm.cancelTransaction();

Please note that writes block each other, and will block the thread they are made on if other writes are in progress. This can cause ANR errors if you are doing writes from the UI thread while also doing writes from a background thread. To avoid this, first create objects in memory first outside a transaction, and only perform a simple Realm.copyToRealm() inside the transaction, which will keep blocking times to a minimum.

Thanks to Realm’s MVCC architecture, reads are not blocked while a write transaction is open! This means that unless you need to make simultaneous writes from many threads at once, you can favor larger write transactions that do more work over many fine-grained write transactions. When you commit a write transaction to a Realm, all other instances of that Realm will be notified, and the read implicit transactions will refresh your Realm objects automatically.

Please note read & write access in Realm is ACID.

Creating objects

Because RealmObjects are strongly tied to a Realm, they should be instantiated through the Realm directly:

realm.beginTransaction();
User user = realm.createObject(User.class); // Create a new object
user.setName("John");
user.setEmail("john@corporation.com");
realm.commitTransaction();

Alternatively you can create an instance of an object first and add it later using realm.copyToRealm(). Realm supports as many custom constructors as you like as long as one of them is a public no arguments constructor.

User user = new User("John");
user.setEmail("john@corporation.com");

// Copy the object to Realm. Any further changes must happen on realmUser
realm.beginTransaction();
User realmUser = realm.copyToRealm(user);  
realm.commitTransaction();

When using realm.copyToRealm() it is important to remember that only the returned object is managed by Realm, so any futher changes to the original object will not be persisted.

Transaction blocks

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

realm.executeTransaction(new Realm.Transaction() {
	@Override
	public void execute(Realm realm) {
		User user = realm.createObject(User.class);
		user.setName("John");
		user.setEmail("john@corporation.com");
	}
});

Asynchronous Transactions

As transactions are blocked by other transactions it can be an advantage to do all writes on a background thread in order to avoid blocking the UI thread. By using an asynchronous transaction, Realm will run that transaction on a background thread and report back when the transaction is done.

To switch from a synchronous transaction to an asynchronous transaction, add the Realm.Transaction.Callback parameter.

realm.executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm bgRealm) {
                User user = bgRealm.createObject(User.class);
                user.setName("John");
                user.setEmail("john@corporation.com");
            }
        }, new Realm.Transaction.Callback() {
            @Override
            public void onSuccess() {
            }

            @Override
            public void onError(Exception e) {
                // transaction is automatically rolled-back, do any cleanup here
            }
        });

The callback is optional, but if provided it will be called when the transaction completes or fails. Callbacks are controlled by the Looper, so only null callbacks are allowed on non-looper threads.

RealmAsyncTask transaction = realm.executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm bgRealm) {
                User user = bgRealm.createObject(User.class);
                user.setName("John");
                user.setEmail("john@corporation.com");
            }
        }, null);

An asynchronous transaction is represented by the RealmAsyncTask object. This object can be used to cancel any pending transaction if you are quitting the Activity/Fragment before the transaction is completed. Forgetting to cancel a transaction can crash the app if the callback updates the UI.

public void onStop () {
    if (transaction != null && !transaction.isCancelled()) {
        transaction.cancel();
    }
}

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.

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

// Build the query looking at all users:
RealmQuery<User> query = realm.where(User.class);

// Add query conditions:
query.equalTo("name", "John");
query.or().equalTo("name", "Peter");

// Execute the query:
RealmResults<User> result1 = query.findAll();

// Or alternatively do the same all at once (the "Fluent interface"):
RealmResults<User> result2 = realm.where(User.class)
                                  .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. Objects are not copied - you get a list of references to the matching objects, and you work directly with the original objects that matches your query. The RealmResults inherits from Java’s AbstractList, and behaves in similar ways. For example, RealmResults are ordered, and you can access the individual objects through an index.

When a query does not have any matches, the returned RealmResults object will not be null, but the size() method will return 0.

If you wish modify or delete any of the objects in a RealmResults, you must do so in a write transaction.

Retrieving objects by type

The most basic method for retrieving objects from a Realm is realm.allObjects(), which returns a RealmResults of all instances of the model class being queried.

There are specialized versions of allObjects() which offer sorting functionality i.e., you can specify sorting order per field. See realm.allObjectsSorted() for details.

Conditions

The following hopefully self explanatory conditions are supported:

  • between, greaterThan(), lessThan(), greaterThanOrEqualTo() & lessThanOrEqualTo()
  • equalTo() & notEqualTo()
  • contains(), beginsWith() & endsWith()

Not all conditions are applicable for all data types. Please consult the API reference for RealmQuery for details.

Modifiers

String conditions can ignore case for characters A-Z and a-z by using the CASE_INSENSITIVE modifier.

Logical Operators

Each condition is implicitly logical-and together. Logical-or must be applied explicitly with or().

You can also group conditions with “parentheses” to specify order of evaluation: beginGroup() is your “left parenthesis” and endGroup() your “right parenthesis”:

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

Futhermore, it is possible to negate a condition with not(). The not() operator can be used with beginGroup()/endGroup() to negate subconditions only.

Sorting

Once you have done your query, you can sort the results like this:

RealmResults<User> result = realm.where(User.class).findAll();
result.sort("age"); // Sort ascending
result.sort("age", RealmResults.SORT_ORDER_DESCENDING);

Chaining Queries

Since results are never copied and computed on request, you can very efficiently chain queries to gradually filter your data:

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

Aggregation

A RealmResults also has various aggregation methods:

RealmResults<User> results = realm.where(User.class).findAll();
long   sum     = results.sum("age").longValue();
long   min     = results.min("age").longValue();
long   max     = results.max("age").longValue();
double average = results.average("age");

long   matches = results.size();

Iterations

To iterate through all objects in a RealmResults you can take advantage of Iterable:

RealmResults<User> results = realm.where(User.class).findAll();
for (User u : results) {
    // ... do something with the object ...
}

or use a traditional for loop:

RealmResults<User> results = realm.where(User.class).findAll();
for (int i = 0; i < results.size(); i++) {
    User u = results.get(i);
    // ... do something with the object ...
}

Deletion

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

// obtain the results of a query
RealmResults<Dog> results = realm.where(Dog.class).findAll();

// All changes to data must happen in a transaction
realm.beginTransaction();

// remove single match
results.remove(0);
results.removeLast();

// remove a single object
Dog dog = results.get(5);
dog.removeFromRealm();

// Delete all matches
results.clear();

realm.commitTransaction()

Asynchronous Queries

Queries can be performed on a background thread.

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

Example: finding users with name “John” or “Peter”

Create the query

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

Note that the query is not blocking and immediately returns a RealmResults<User>. This is a promise similar to the concept of Future in standard Java. The query will continue to run in a background thread, and once it completes it will update the returned instance of RealmResults.

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

Register a callback

public void onStart() {
    RealmResults<User> result = realm.where(User.class).findAllAsync();
     result.addChangeListener(
        new RealmChangeListener() {
            @Override
            public void onChange() { // called once the query complete and on every update
            // use the result
            }
        });
}

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

public void onStop () {
    result.removeChangeListener(callback); // remove a particular listener
    // or
    result.removeChangeListeners(); // remove all registered listeners
}

Check if the query has completed

if (result.isLoaded()) {
  // Results are now available
}

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

Force load an asynchronous query

Optionally you can wait until the query completes. This will block the current thread, making the query synchronous again (same concept as in Future.get()).

result.load() // be careful, this will block the current thread until it returns

Non-Looper threads

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.

Realms

Realms are our equivalent of a database: they contain different kinds of objects, and map to one file on disk.

The Default Realm

You may have noticed so far that we have always initialized our realm variable by calling Realm.getInstance(Context context). This static constructor will return a Realm instance for your thread, that maps to a file called default.realm located in Context.getFilesDir().

The file is located at the root of the writable directory for your application. As Realm uses internal storage for the default Realm, your app does not require any read or write permissions. In most cases, you can find the file in the folder /data/data/<packagename>/files/.

It is always possible to obtain the absolute path of a realm by using the realm.getPath() method.

It is important to note that Realm instances are thread singletons, meaning that the static constructor will return the same instance for every thread.

Configuring a Realm

Calling Realm.getInstance(context) makes it easy to get started with Realm. For more fine-grained control, it is possible to create a RealmConfiguration object that controls all aspects of how a Realm is created.

// The RealmConfiguration is created using the builder pattern.
RealmConfiguration config = new RealmConfiguration.Builder(context)
  .name("myrealm.realm")
  .encryptionKey(getKey())
  .schemaVersion(42)      
  .setModules(new MySchemaModule())
  .migration(new MyMigration())    
  .build();

// These two are equivalent
Realm realm = Realm.getInstance(context);
Realm realm = Realm.getInstance(new RealmConfiguration.Builder(context).build());

The RealmConfiguration can be saved as a default configuration. Setting a default configuration in your custom Application class, will ensure that it is available in the rest of your code.

public class MyApplication extends Application {
  @Override
  public void onCreate() {
    super.onCreate();
    RealmConfiguration config = new RealmConfiguration.Builder(context).build();
    Realm.setDefaultConfiguration(config);
  }
}

public class MyActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Realm realm = Realm.getDefaultInstance();
  }
}

It is also possible to have multiple RealmConfigurations. In this way you can control the version, schema and location of each Realm independently.

RealmConfiguration myConfig = new RealmConfiguration.Builder(context)
  .name("myrealm.realm").
  .schemaVersion(2)
  .setModules(new MyCustomSchema())
  .build();

RealmConfiguration otherConfig = new RealmConfiguration.Builder(context)
  .name("otherrealm.realm")
  .schemaVersion(5)
  .setModules(new MyOtherSchema())
  .build();

Realm myRealm = Realm.getInstance(myConfig);
Realm otherRealm = Realm.getInstance(otherConfig);

In-Memory Realm

Define an instance for an un-persisted in-memory Realm:

RealmConfiguration myConfig = new RealmConfiguration.Builder(context)
    .name("myrealm.realm")
    .inMemory()
    .build();

Setting this will create an in-memory Realm instead of saving it to disk. 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.

Please note that creating an in-memory Realm with the same name as a regular (persisted) Realm is not allowed.

When all in-memory Realm instances with a particular name go out of scope with no references, all data is freed for that Realm. It is recommended that you hold onto a reference to any created in-memory Realms for the duration of your App.

Using a Realm across Threads

The only rule to using Realm across threads is to remember that Realm, RealmObject or RealmResults instances cannot be passed across threads. However, you can use an asynchronous query or asynchrounous 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 & writeable from any thread!

Closing Realm instances

Realm implements Closeable in order to take care of native memory deallocation and file descriptors so it is important to remember to close your Realm instances when you are done with them.

Realm instances are reference counted, which means that if you call getInstance() twice in a thread, you will also have to call close() twice as well. This allows you to implement Runnable classes without having to worry in what thread they will be executed: simply start it with a getInstance() and end it with a close() and you are good to go!

For the UI thread the easiest way is to execute realm.close() in the onDestroy() method.

For AsyncTask this is a good pattern (as it is for any Closeable):

protected Long doInBackground(Context... contexts) {
    Realm realm = null;
    try {
        realm = Realm.getInstance(contexts[0]);

        // ... Use the Realm instance
    } finally {
        if (realm != null) {
            realm.close();
        }
    }
}

If you need to create another Looper thread other than the UI one you can use this pattern:

public class MyThread extends Thread {
    private final Context;

    public MyThread(Context context) {
        this.context = context;
    }

    public void run() {
        Looper.prepare();
        Realm realm = null;
        try {
            realm = Realm.getInstance(context);

            //... Setup the handlers using the Realm instance
            Lopper.loop();
        } finally {
            if (realm != null) {
                realm.close();
            }
        }
    }
}

If you have the luck to work on an app with minSdkVersion >= 19 then you can use try-with-resources:

try (Realm realm = Realm.getInstance(context)) {
	// No need to close the Realm instance manually
}

Auto-Refresh

If a Realm instance has been obtained from a thread that is associated with a Looper (the UI thread is by default) then the Realm instance comes with an auto-refresh feature. This means that the Realm instance will be automatically updated to the latest version on every occurrence of the event loop. This is a handy feature that allows you to keep your UI constantly updated with the latest content with very little effort.

If you get a Realm instance from a thread that does not have a Looper attached, then such instance will not auto-update unless the refresh() method is called. It is important to note that having to hold 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 be sure wether your Realm instance has auto-refresh activated or not you can use the isAutoRefresh() method.

Finding a Realm File

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

Schemas

The default schema for a Realm is defined as all the Realm model classes in a project. It is possible to change this behavior, e.g. if you want to restrict a Realm to only contain a subset of classes. This is done by creating a custom RealmModule.

// Create the module
@RealmModule(classes = { Person.class, Dog.class })
public class MyModule {
}

// Set the module in the RealmConfiguration to allow only classes defined by the module.
RealmConfiguration config = new RealmConfiguration.Builder(context)
  .setModules(new MyModule())
  .build();

// It is possible to combine multiple modules to one schema.
RealmConfiguration config = new RealmConfiguration.Builder(context)
  .setModules(new MyModule(), new MyOtherModule())
  .build();

Sharing schemas

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 otherwise conflict with the default RealmModule being generated by the app. The library’s RealmModule is also how the library exposes its Realm classes to the app.

// 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)
public class MyLibraryModule {
}

// Library projects are therefore required to explicitly set their own module.
RealmConfiguration libraryConfig = new RealmConfiguration.Builder(context)
  .name("library.realm")
  .setModules(new MyLibraryModule())
  .build();

// Apps can add the library RealmModule to their own schema.
RealmConfiguration config = new RealmConfiguration.Builder(context)
  .name("app.realm")
  .setModules(Realm.getDefaultModule(), new MyLibraryModule())
  .build();

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

Relationships

Any two RealmObjects can be linked together.

public class Email extends RealmObject {
    private String address;
    private boolean active;
    // ... setters and getters left out
}

public class Contact extends RealmObject {
    private String name;
    private Email email;
    // ... setters and getters left out
}

Relationships are generally cheap in Realm. This means that following a link is not expensive in terms of speed, and the internal presentation of relationships is highly efficient in terms of memory consumption.

Many-to-One

Simply declare a property with the type of one of you RealmObject subclasses:

public class Contact extends RealmObject {
    private Email email;
    // Other fields…
}

Each contact (instance of Contact) have either 0 or 1 email (instance of Email). In Realm, nothing prevent you from using the same email object in multiple contacts, and the model above can be a many-to-one relationship but often used to model one-to-one relationships.

Setting the RealmObject field to null will clear the reference but the object will not be deleted from the Realm.

Many-to-Many

You can establish a relationship to 0, 1 or more objects from a single object via a RealmList field declaration

public class Contact extends RealmObject {
    private RealmList<Email> emails;
    // Other fields…
}

RealmList are basically containers of RealmObjects, that behave very much like a regular Java List. There is no limitation in Realm to using the same object twice (or more) in different RealmList, and you can use this to model both one-to-many, and many-to-many relationsships.

You can add standard getters & setters to access the data in the link.

realm.beginTransaction();
Contact contact = realm.createObject(Contact.class);
contact.setName("John Doe");

Email email1 = realm.createObject(Email.class);
email1.setAddress("john@example.com");
email1.setActive(true);
contact.getEmails().add(email1);

Email email2 = realm.createObject(Email.class);
email2.setNumber("jd@example.com");
email2.setActive(false);
contact.getEmails().add(email2);

realm.commitTransaction();

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

public class Person extends RealmObject {
    private String name;
    private RealmList<Person> friends;
    // Other fields…
}

Use recursive relationships with care as Realm does not currently have cycle detection and you can easily end in infinite loops.

Setting the value to null for a RealmList field will clear the list. That is, the list will be empty (length zero), but no objects have been deleted. The getter for a RealmList will never return null. The returned object is always a list but the length might be zero.

It is possible to query links or relationships. Consider the model above. If you wish to find all contacts with an active email address, you can do:

RealmResults<Contact> contacts = realm.where(Contact.class).equalTo("emails.active", true).findAll();

First of all, notice that the field name in the equalsTo condition contains the path through the relationships (separated by period .).

The query above should be read “give me all contacts with at least one active email address”. It is important to understand that the result will contain the Email objects which do not fulfill the condition since they are part of the Contact objects.

Moreover, each condition in a link query is evaluated separately. The final result is the intersection of the results of the link queries. This implies that the following query will give you all contacts with at least one active and at least one inactive email addresses:

RealmResults<Contact> contacts = realm.where(Contact.class).equalTo("emails.active", true).equalTo("emails.active", false).findAll();

JSON

It is possible to add RealmObjects represented as JSON directly to Realm whether they are represented as a String, a JSONObject or a InputStream. Realm will ignore any properties in the JSON not defined by the RealmObject. Single objects are added through Realm.createObjectFromJson() while lists of objects are added using Realm.createAllFromJson().

// A RealmObject that represents a city
public class City extends RealmObject {
    private String city;
    private int id;
    // getters and setters left out ...
}

// Insert from a string
realm.beginTransaction();
realm.createObjectFromJson(City.class, "{ city: \"Copenhagen\", id: 1 }");
realm.commitTransaction();

// Insert multiple items using a InputStream
InputStream is = new FileInputStream(new File("path_to_file"));
realm.beginTransaction();
try {
    realm.createAllFromJson(City.class, is);
    realm.commitTransaction();
} catch (IOException e) {
    realm.cancelTransaction();
}

Parsing JSON with Realm is subject to the following rules.

  • Creating object with JSON which has the field with a null value:
    • For a not-required field, set it to null which is the default value.
    • For a required field, throw an exception.
  • Updating object with JSON which has the field with a null value:
    • For a not-required field, set it to null.
    • For a required field, throw an exception.
  • JSON doesn’t have the field:
    • Leave the value unchanged for both required and not-required fields.

Notifications

Since 0.80.3, the RealmChangeListener is managed as a weak reference internally to avoid potential leaks. So DO NOT use anonymous RealmChangeListener when calling addListener. Instead, always maintain the reference to your listeners until you don’t need them anymore.

If you have a background thread adding data to a Realm, your UI or other threads can get notified of changes in a realm by adding a listener, which is executed when the Realm is changed (by another thread or process):

public class MyActivity extends Activity {
    private Realm realm;
    // A reference to RealmChangeListener needs to be held to avoid being
    // removed by the garbage collector.
    private RealmChangeListener realmListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      realm = Realm.getDefaultInstance();
      reamlListener = new RealmChangeListener() {
        @Override
        public void onChange() {
            // ... do something with the updates (UI, etc.) ...
        %>;
      realm.addChangeListener(realmListener);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // Remove the listener.
        realm.removeChangeListener(realmListener);
        // Close the realm instance.
        realm.close();
    }
}

You can easily close all listeners when needed:

realm.removeAllChangeListeners();

Migrations

Migrations are a work in progress. The feature is fully functional, but the current interface is cumbersome, and will be rewritten soon.

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

Just changing your code to the new definition will work fine, if you have no data stored on disk under the old database schema. But if you do, there will be a mismatch between what Realm sees defined in code & the data Realm sees on disk, so an exception will be thrown.

We provide built-in methods so you can upgrade your schema on disk, and the data you stored for previous versions of the schema. See our migrationSample app for 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 very often, and you are OK with losing all your data, you can delete your .realm file on disk (and the entire dataset it contained!) instead of having to write a migration. This can be helpful when tinkering with models early in the development cycle of your app.

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 stored encrypted on disk by passing a 512-bit encryption key to Realm.getInstance():

byte[] key = new byte[64];
new SecureRandom().nextBytes(key);
Realm realm = Realm.getInstance(this, key);

// ... use the Realm as normal ...

This ensures that all data persisted to disk is transparently encrypted and decrypted with standard AES-256 encryption. The same encryption key must be supplied each time a Realm instance for the file is created.

See examples/encryptionExample for a complete example of how to securely store keys between runs in the Android KeyStore so that other applications cannot read them.

Adapter

Realm provides an abstract utility class to help binding data coming from RealmResults to UI widgets. The RealmBaseAdapter class will take care of all required wiring if you implement the getView() method:

public class Person extends RealmObject {
    private String name;
    public String getName() {
        return this.name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

public class MyAdapter extends RealmBaseAdapter<Person> implements ListAdapter {

    private static class MyViewHolder {
        TextView name;
    }

    public MyAdapter(Context context, int resId,
                     RealmResults<Person> realmResults,
                     boolean automaticUpdate) {
        super(context, realmResults, automaticUpdate);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;
        if (convertView == null) {
            convertView = inflater.inflate(android.R.layout.simple_list_item_1, 
                                           parent, false);
            viewHolder = new ViewHolder();
            viewHolder.name = (TextView) convertView.findViewById(android.R.id.text1);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        Person item = realmResults.get(position);
        viewHolder.name.setText(item.getName());
        return convertView;
    }

    public RealmResults<Person> getRealmResults() {
        return realmResults;
    }    
}

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. When using Realm with GSON 2.3.1 (latest version), you have to specify an ExclusionStrategy.

// Using the User class
public class User extends RealmObject {
    private String name;
    private String email;
    // getters and setters left out ...
}

Gson gson = new GsonBuilder()
        .setExclusionStrategies(new ExclusionStrategy() {
            @Override
            public boolean shouldSkipField(FieldAttributes f) {
                return f.getDeclaringClass().equals(RealmObject.class);
            }

            @Override
            public boolean shouldSkipClass(Class<?> clazz) {
                return false;
            }
        })
        .create();

String json = "{ name : 'John', email : 'john@corporation.com' }";
User user = gson.fromJson(json, User.class);

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

Some JSON APIs will return arrays of primitive types like integers or Strings, which Realm doesn’t support yet. 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.

Otto

Otto is an event bus from Square. Otto works with Realm out of the box, but there are some timing and thread issues to be aware of.

Otto normally receives an event on the same thread it was sent. This means that it is possible to add a RealmObject to an event and read its data in the receiver method without any problems. However if you are using the hack described here to always post on the main thread, you cannot have RealmObjects as part of your event data unless you always send events from the UI thread also. This is normally done to be able to manipulate UI elements in response to an event which is only possible from the main thread.

When a RealmObject is changed in one thread, Realm schedules a refresh of Realm data on other threads using a Handler. Otto.post(event) on the other hand, dispatch events immediately. So if you post an event to another thread to notify about changes to Realm data, you will have to manually call realm.refresh() to get the latest data.

@Subscribe
public void handleEvent(OttoEvent event) {
    realm.refresh();
    // Continue working with Realm data loaded in this thread
}

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.

// 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 = { PersonRealmProxy.class },
        value = Parcel.Serialization.BEAN,
        analyze = { Person.class })
public class Person extends 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 and 2) Once an object has been parcelled, it becomes detached from Realm and at this point behaves like a standalone 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.

As Retrofit uses GSON internally, it also needs a properly configured GsonConverter if you want to deserialize network JSON data to RealmObjects.

Gson gson = new GsonBuilder()
        .setExclusionStrategies(new ExclusionStrategy() {
            @Override
            public boolean shouldSkipField(FieldAttributes f) {
                return f.getDeclaringClass().equals(RealmObject.class);
            }

            @Override
            public boolean shouldSkipClass(Class<?> clazz) {
                return false;
            }
        })
        .create();

// Configure Retrofit to use the proper GSON converter
RestAdapter restAdapter = new RestAdapter.Builder()
    .setEndpoint("https://api.github.com")
    .setConverter(new GsonConverter(gson))
    .build();

GitHubService service = restAdapter.create(GitHubService.class);

Retrofit does not automatically add objects to Realm, instead you must manually add them using the realm.copyToRealm() or realm.copyToRealmOrUpdate() method.

GitHubService service = restAdapter.create(GitHubService.class);
List<Repo> repos = service.listRepos("octocat");

// Copy elements from Retrofit to Realm to persist them.
realm.beginTransaction();
List<Repo> realmRepos = realm.copyToRealmOrUpdate(repos);
realm.commitTransaction();

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

Next Steps

Take a look at our examples to see Realm used in practice in an app.

Happy hacking! You can always talk to a live human developer on realm-java.

Current limitations

Realm is currently in beta and we are continuously adding features and fixing issues while working towards a 1.0 release. Until then, we’ve compiled a list of our most commonly hit limitations.

Please refer to our GitHub issues for a more comprehensive list of known issues.

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 for Android prepend 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. The dates are truncated with a precision of one second.
  4. Nested transactions are not supported, and an exception is throw if it is detected.
  5. Strings and byte arrays (byte[]) cannot be larger than 16 MB.
  6. Case insensitive string matches in queries are only supported for character sets in ‘Latin Basic’, ‘Latin Supplement’, ‘Latin Extended A’, ‘Latin Extended B’ (UTF-8 range 0-591).

Objects

Due to how the proxy classes override getters and setters in the model classes there are some restrictions to what is allowed in a model class:

  • Only private instance fields.
  • Only default getter and setter methods.
  • Static fields, both public and private.
  • Static methods.
  • Implementing interfaces with no methods.

This means that it is currently not possible to extend anything else than RealmObject or to override methods like toString() or equals(). Also it is only possible to implement interfaces. We are working on lifting these restrictions.

Sorting

Sorting is currently limited to character sets in ‘Latin Basic’, ‘Latin Supplement’, ‘Latin Extended A’, ‘Latin Extended B’ (UTF-8 range 0-591). For other charsets, sorting will not change the RealmResults object.

Case insensitive queries

Setting the caseSensitive flag when using equalTo, contain, endsWith or beginsWith will only work on characters from the English locale. 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. Moreover, asynchronous queries are currently not supported. The thread example shows how to use Realm in a multithreading environment.

Migration

The migration support has not matured yet, and you have to rely on a number of internal classes. We plan to have easy-to-use migration support in the future but currently the best option is to look at the migration example.

Realm files cannot be accessed by concurrent processes

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. Multi-process support is coming soon.

FAQ

How can 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 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.

Should I use Realm in production applications?

Realm has been used in production in commercial products since 2012.

You should expect our Java APIs to break as we evolve the product from community feedback — and you should expect more features & bugfixes to come along as well.

Do I have to pay to use Realm?

No, Realm for Android is entirely free to use, even in commercial projects.

How do you all plan on making money?

We’re actually already generating revenue selling enterprise products and services around our technology. If you need more than what is currently in our releases or in realm-java, we’re always happy to chat by email. Otherwise, we are committed to developing realm-java in the open, and to keep it free and open-source under the Apache 2.0 license.

I see references to a “core” in the code, what is that?

The core or Realm Core is our C++ storage engine. The core is not currently open-source but we do plan on open-sourcing it, also under the Apache 2.0 license, once we’ve had a chance to clean it, rename it, and finalize major features inside of it. In the meantime, its binary releases are made available under the Realm Core Binary License.

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

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

This has a two implications: Realm objects are generally more lightweight than normal Java objects and Realm objects automatically always have the newest data where Java object needs to be updated manually.

Why do model classes need to extend RealmObject?

The reason for this is so we can add Realm specific functionality to your model classes. Currently only removeFromRealm(), but others might show up. It also allows us to use generics in our APIs, making it easier to read and use.

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 the IDE you won’t notice any difference.

Why do I need to have getters and setters for all my fields?

This is a result of how our proxy classes works.

To ensure that all field accesses use the database instead of a local copy of the data, all field accessors are overriden by the proxy classes. This is only possible in Java with private fields with getters and setters.

This also has the implication that you need to use the getters and setters in all private methods as well as when implementing interfaces like Comparable.

It is not an ideal situation and we would love to get rid of this requirement. Some solutions like AspectJ or Javassist might make it possible but we are still investigating the possibilities.

A consequence of proxy classes overriding setters and getters is that you cannot create customised versions of setters and getters. A workaround is to use an ignored field (the @Ignore annotation), and use its setter and getter to add your customisation to. A model class found look like:

package io.realm.entities;

import io.realm.RealmObject;
import io.realm.annotations.Ignore;

public class StringOnly extends RealmObject {

    private String name;

    @Ignore
    private String kingName;

    // custom setter
    public void setKingName(String kingName) { setName("King " + kingName); }

    // custom getter
    public String getKingName() { return getName(); }

    // setter and getter for 'name'
}

You can then use the setKingName() as a custom setter instead of setName(). Please note that the custom setter uses setName() and does not assign directly to the field.

Why can I not create a RealmList myself?

While a RealmList does look like an ordinary List, it is not. It is our way of representing relationships and thus needs to be managed by Realm. This is the reason for the protected constructor, and why it is created for you when calling Realm.createObject().

We do have plans however to add functionality to allow easy mapping of standard Lists to RealmLists.

Why can I not create instances of RealmObjects myself?

This is due to the same reasons as for RealmList. The RealmObject is a proxy for the data in the database, and needs to be managed by Realm to work correctly.

Just like for RealmLists we plan to add functionality to convert your own initialized model objects into proper Realm objects.

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.

What to do about 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 io.realm.internal.OutOfMemoryError exception, and your app has run out of memory. It is important not to ignore this exception by having an empty catch block or a too broad catch. If your app does continue running, acessing the Realm file might leave your Realm file in a corrupted or inconsistent state. In the case of io.realm.internal.OutOfMemoryError, 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.

In order to give you a consistent view of your data, Realm operates on multiple versions of a realm. If you read some data from a realm and then block the thread on a long-running operation while writing to the realm on other threads, the version is never updated and Realm has to hold on to intermediate versions of the data which you may not actually need, resulting in the file size growing steadily. (This extra space would eventually be reused by future writes, or could be compacted — for example by calling compactRealmFile.)

What does the exception ‘Annotation processor may not have been executed.’ mean?

During compilation of your app, the model classes are processed and proxy classes are generated. If this annotation process fails, the proxy classes or their methods cannot be found. When your app begins running, it Realm will throw exception with message ‘Annotation processor may not have been executed.’. You may see this in case you use Java 6 as it doesn’t support inheriting annotations. You then have to add @RealmClass before your models. Otherwise it can often be solved by removing/cleaning all generated or intermediate files and rebuild.

Android Chromium WebView

Note: This bug has been fixed with v43 of the WebView.

Starting with 5.0 Lollipop, Android began shipping a Chromium WebView that can be installed and updated through the Play Store. Unfortunately there is a bug in the latest version of this webview (v40), that can cause encrypted Realms to crash if used together.

The current work around is to either downgrade the WebView to v39, or to make sure to call CookieManager.getInstance() before opening the encrypted Realm.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_webview);
    CookieManager.getInstance(); // Prevent Realm from crashing
    Realm realm = Realm.getInstance(this, getKey())
}

Details can be found here

Encryption is not supported on this device Exception

A few older devices (HTC One X for example) does not work correctly with signal handlers. Realm encryption currently relies on the signal handler which means encryption of Realm doesn’t work on those devices. The same problem on HTC One X happened to Firefox for Android as well. See On-demand decompression startup failure with Firefox on the HTC One X (Android 4.2.2) for more details.

From v0.82.2 Realm tries to detect if the device has this problem when the encrypted Realm is opened, and throws a RealmEncryptionNotSupportedException on those devices.

Please consider catching the RealmEncryptionNotSupportedException and use Realm without encryption on those devices instead for now.

We are working on an alternative solution for encryption which will support those devices as well in the future.