Realm Java enables you to efficiently write your app’s model layer in a safe, persisted and fast way. Here’s what it looks like:

// Define you model class by extending the RealmObjectpublicclassDogextendsRealmObject{@Required// Name cannot be nullprivateStringname;privateintage;// ... Generated getters and setters ...}publicclassPersonextendsRealmObject{@Required// Name is not nullableprivateStringname;privateStringimageUrl;// imageUrl is an optional fieldprivateRealmList<Dog>dogs;// A person has many dogs (a relationship)// ... Generated getters and setters ...}// Use them like regular java objectsDogdog=newDog();dog.setName("Rex");dog.setAge(1);Log.v(TAG,"Name of the dog: "+dog.getName());// Create a RealmConfiguration which is to locate Realm file in package's "files" directory.RealmConfigurationrealmConfig=newRealmConfiguration.Builder(context).build();// Get a Realm instance for this threadRealmrealm=Realm.getInstance(realmConfig);// Query Realm for all dogs less than 2 years oldfinalRealmResults<Dog>puppies=realm.where(Dog.class).lessThan("age",2).findAll();puppies.size();// => 0 because no dogs have been added to the Realm yet// Listeners will be notified when data changespuppies.addChangeListener(newRealmChangeListener<RealmResults<Dog>>(){@OverridepublicvoidonChange(RealmResults<Dog>results){// Queries are updated in real timepuppies.size();// => 1}});// Persist your data easilyrealm.beginTransaction();realm.copyToRealm(dog);realm.commitTransaction();// Query and update the result asynchronously in another threadrealm.executeTransactionAsync(newRealm.Transaction(){@Overridepublicvoidexecute(Realmrealm){// begin & end transcation calls are done for youDogtheDog=realm.where(Dog.class).equals("age",1).findFirst();theDog.setAge(3);}},newRealm.Transaction.Callback(){@OverridepublicvoidonSuccess(){// Original Queries and Realm objects are automatically updated.puppies.size();// => 0 because there are no more puppies (less than 2 years old)dog.getAge();// => 3 the dogs age is updated}});

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

applyplugin:'realm-android'

The application level build.gradle is located here:

Once these two changes are made, simply refresh your gradle dependencies. If you are upgrading from a version prior to v0.88 you may also need to clean your gradle project (./gradlew clean) to remove any lingering previous installations.

API Reference

Examples

Take a look at our examples to see Realm used in practice in an app. You just Import Project in Android Studio and hit run.

The introExample contains simple examples of how you use the current 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 to bind RealmResults to Android lists in a convenient way.

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. Only Boolean, Byte, Short, Integer, Long, Float, Double, String, byte[] and Date can be annotated with Required. Compiling will fail when fields with other types have the @Required annotation. Fields with primitive types and the RealmList type are required implicitly. Fields with RealmObject type are always nullable.

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.

Auto-Updating Objects

RealmObjects are live, auto-updating views into the underlying data, which means objects never have to be refreshed. Modifying objects that affect the query will be reflected in the results immediately.

This property of all RealmObject’s and 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 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, indicating when your app’s UI should be refreshed.

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 (String) or integer (byte, short, int, or long) and its boxed variants (Byte, Short, Integer, and 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.

MyObjectobj=newMyObject();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 insteadrealm.copyToRealmOrUpdate(obj);realm.commitTransaction();

For String (String) and boxed integer (Byte, Short, Integer, and Long), Primary keys can have the value null unless the @PrimaryKey annotation is additionally combined with @Required annotation.

Limitations

Currently there’s no support for final, transient and volatile fields. This is mainly to avoid discrepancies between how an object would behave as managed by Realm or standalone.

Realm data models are not allowed to extend any other object than RealmObject.

RealmModel interface

An alternative to extending the RealmObject base class is implementing the RealmModel interface and adding the @RealmClass annotation.

@RealmClass
public class User implements RealmModel {
}

All methods available on RealmObject are then available through static methods.

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

Relationships

Any two RealmObjects can be linked together.

publicclassEmailextendsRealmObject{privateStringaddress;privatebooleanactive;// ... setters and getters left out}publicclassContactextendsRealmObject{privateStringname;privateEmailemail;// ... 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:

publicclassContactextendsRealmObject{privateEmailemail;// 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<T> field declaration

publicclassContactextendsRealmObject{privateRealmList<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 relationships.

Using the Contact and Email classes:

publicclassEmailextendsRealmObject{privateStringaddress;privatebooleanactive;// ... setters and getters left out}publicclassContactextendsRealmObject{privateStringname;privateEmailemail;// ... setters and getters left out}

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

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

publicclassPersonextendsRealmObject{privateStringname;privateRealmLink<Person>friends;// Other fields…}

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.

Link queries

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

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 read, find all Persons who have dogs who are ‘Brown’. It is important to understand that the result will contain the Dog objects which do not fulfill the condition since they are part of the Person’s object:

Notice how the first query returned both Person objects because the condition matched both persons. Each Person in the query result contains a list of Dog objects - all of their dog objects (even ones that do not fulfill the original query condition). Remember, we’re searching for people who have particular kinds of dogs (names and colors), not the actual dogs themselves. Therefore, the second query will be evaluated against the first Person query result (r1) and each of the Persons dogs. The second query also matches both persons as well, but this time it’s because of the color of the dog.

Let’s dig a little deeper to help solidify this concept. Please review the following example:

The first query should read, find all Persons who have dogs named ‘Fluffy’ and also find all Persons who have dogs who are ‘Brown’ and then give me the intersection of the two. The second query should read, find all Persons who have dogs named ‘Fluffy’. Then, given that result set, find all Persons who have dogs whose color is ‘Brown’ and given that result set find all Persons who have dogs whose color is ‘Yellow’.

Let’s take a look at the query behind r1 to fully understand what is happening. The two conditions are equalTo("dogs.name", "Fluffy") and equalTo("dogs.color", "Brown"). The first condition is fulfilled for U1 and U2 - this is set C1. The second condition is also fulfilled for U1 and U2 - this is set C2. The logical-and in the query is the same as an intersection of the two sets C1 and C2. The intersection between C1 and C2 is U1 and U2. Therefore, r1 is U1 and U2.

The query behind r2 is different. Let’s begin by breaking this query apart. The first portion of the query looks like this: RealmResults<Person> r2a = realm.where(Person.class).equalTo("dogs.name", "Fluffy").findAll();. It matches U1 and U2. Then, r2b = r2a.where().equalTo("dogs.color", "Brown").findAll(); also matches U1 and U2 (both persons have brown dogs). The final query, r2 = r2b.where().equalTo("dogs.color", "Yellow").findAll(); matches only U2 since the only person in the brown dog result set that has a Yellow dog is U2.

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.

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:

Please note that write transactions block each other. This can cause ANR errors if you are creating 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.

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

Useruser=newUser("John");user.setEmail("[email protected]");// Copy the object to Realm. Any further changes must happen on realmUserrealm.beginTransaction();UserrealmUser=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 further 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.

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.

realm.executeTransactionAsync(newRealm.Transaction(){@Overridepublicvoidexecute(RealmbgRealm){Useruser=bgRealm.createObject(User.class);user.setName("John");user.setEmail("[email protected]");}},newRealm.Transaction.OnSuccess(){@OverridepublicvoidonSuccess(){// Transaction was a success. }},newRealm.Transaction.OnError(){@OverridepublicvoidonError(Throwableerror){// Transaction failed and was automatically canceled.}});

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

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.

Updating strings and byte arrays

Realm is working on entire fields, and it is not possible to update individual elements of strings or byte arrays. Suppose you need to update the 5th element of a string, you will have to do something like

// 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.

Note that query chains are built on RealmResults, not RealmQuery. If you add more conditions to an existing RealmQuery, then you are modifying the query, not the chains. Read more about link queries.

Auto-Updating Results

RealmResults are live, auto-updating views into the underlying data, which means results never have to be re-fetched. Modifying objects that affect the query will be reflected in the RealmResults in the next Looper event.

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 store the Realm object or RealmResults in a field and access it without having to make sure to refresh its data prior to each access.

You can subscribe to Realm notifications to know when Realm data is updated, indicating when your app’s UI should be refreshed, without having to re-fetch your RealmResults.

Since results are auto-updating, it’s important to not rely on indices & counts staying constant.

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.

Instead use the deleteFromRealm() method directly on the RealmResults:

RealmResults<User>users=getUsers();realm.beginTransaction();users.deleteFromRealm(0);// Delete and remove object directlyrealm.commitTransaction();for(Useruser:users){showUser(user);// Deleted user will not be shown}

Deletion

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

// obtain the results of a queryRealmResults<Dog>results=realm.where(Dog.class).findAll();// All changes to data must happen in a transactionrealm.beginTransaction();// remove single matchresults.deleteFromRealm(0);results.deleteLastFromRealm();// remove a single objectDogdog=results.get(5);dog.deleteFromRealm();// Delete all matchesresults.deleteAllFromRealm();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

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 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).

Register a callback

privateRealmChangeListenercallback=newRealmChangeListener(){@OverridepublicvoidonChange(){// called once the query complete and on every update// use the result}};publicvoidonStart(){RealmResults<User>result=realm.where(User.class).findAllAsync();result.addChangeListener(callback);}

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

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()).

RealmResults<User>result=realm.where(User.class).findAllAsync();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.

Configuring a Realm

RealmConfiguration object is used to control all aspects of how a Realm is created. The minimal configuration usable by Realm is:

The above configuration will point to a file called default.realm located in Context.getFilesDir().

A typical configuration would be something like below:

// The RealmConfiguration is created using the builder pattern.// The realm file will be located in Context.getFilesDir() with name "myrealm.realm"RealmConfigurationconfig=newRealmConfiguration.Builder(context).name("myrealm.realm").encryptionKey(getKey()).schemaVersion(42).modules(newMySchemaModule()).migration(newMyMigration()).build();// Use the configRealmrealm=Realm.getInstance(config);

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

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.

The Default RealmConfiguration

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.

publicclassMyApplicationextendsApplication{@OverridepublicvoidonCreate(){super.onCreate();// The realm file will be located in Context.getFilesDir() with name "default.realm"RealmConfigurationconfig=newRealmConfiguration.Builder(this).build();Realm.setDefaultConfiguration(config);}}publicclassMyActivityextendsActivity{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);Realmrealm=Realm.getDefaultInstance();// ... Do something ...realm.close();}}

In-Memory Realm

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.

Dynamic Realms

When working with a conventional Realm, the data model is defined using RealmObject subclasses. This has a lot of benefits with regards to type safety, but in some cases these types are not available at compile time e.g. during migrations or when working with string based data like CSV files.

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 are done using Strings instead of Classes.

Dynamic Realms are opened using the same configuration as conventional Realms, but they ignore any configured schema, migration, and schema version.

RealmConfigurationrealmConfig=newRealmConfiguration.Builder(context).build();DynamicRealmrealm=DynamicRealm.getInstance(realmConfig);// In a DynamicRealm all objects are DynamicRealmObjectsDynamicRealmObjectperson=realm.createObject("Person");// All fields are accessed using stringsStringname=person.getString("name");intage=person.getInt("age");// An underlying schema still exists, so accessing a field that does not exist// will throw an exceptionperson.getString("I don't exist");// Queries still work normallyRealmResults<DynamicRealmObject>persons=realm.where("Person").equalTo("name","John").findAll();

A DynamicRealm trades type safety and performance for flexibility, so only use it in cases where you really need the flexibility.

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.

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

publicclassMyThreadextendsThread{privateRealmrealm;publicvoidrun(){Looper.prepare();try{realm=Realm.getDefaultInstance();//... 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(Realmrealm=Realm.getDefaultInstance()){// 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.

Threading

There’s actually very little you need to know, or do, when working with various threads with Realm. The key takeaway here is that 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 threads will be updated in near real time (meaning that if they’re currently in the process of doing something the update will happen in the next iteration of the runloop).

The only limitation is that you cannot randomly pass Realm objects between threads. If you need the same data on another thread you just need to query for that data on the that 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.

Check out the example below.

Realm Threading Example

Assume we have an app that displays a list of customers. In a background thread (an Android Service) we poll a remote endpoint for new customers and them 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@OverridepublicvoidonActivityCreated(BundlesavedInstanceState){// ... boilerplate omitted for brevityrealm=Realm.getDefaultInstance();// get all the customersRealmResults<Customer>customers=realm.where(Customer.class).findAllAsync();// ... build a list adapter and set it to the ListView/RecyclerView/etc// set up a Realm change listenerchangeListener=newRealmChangeListener(){@OverridepublicvoidonChange(){// 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.refresh() instead.listAdapter.notifyDataSetChanged();// Update the UI}};// 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 threadpublicclassPollingServiceextendsService{@OverridepublicintonStartCommand(Intentintent,intflags,intstartId){Realmrealm=Realm.getDefaultInstance();// go do some network calls/etc and get some data and stuff it into a 'json' varStringjson=customerApi.getCustomers();realm.beginTransaction();realm.createObjectFromJson(Customer.class,json);// Save a bunch of new Customer objectsrealm.commitTransaction();// At this point, the data in the UI thread is already up to date.// ...}// ...}

Once the background service adds new customers to the UI, 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.

That’s all there is to it.

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 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 & writeable from any thread.

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})publicclassMyModule{}// Set the module in the RealmConfiguration to allow only classes defined by the module.RealmConfigurationconfig=newRealmConfiguration.Builder(context).modules(newMyModule()).build();// It is possible to combine multiple modules to one schema.RealmConfigurationconfig=newRealmConfiguration.Builder(context).modules(newMyModule(),newMyOtherModule()).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)publicclassMyLibraryModule{}// Library projects are therefore required to explicitly set their own module.RealmConfigurationlibraryConfig=newRealmConfiguration.Builder(context).name("library.realm").modules(newMyLibraryModule()).build();// Apps can add the library RealmModule to their own schema.RealmConfigurationconfig=newRealmConfiguration.Builder(context).name("app.realm").modules(Realm.getDefaultModule(),newMyLibraryModule()).build();

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

// A RealmObject that represents a citypublicclassCityextendsRealmObject{privateStringcity;privateintid;// getters and setters left out ...}// Insert from a stringrealm.beginTransaction();realm.createObjectFromJson(City.class,"{ city: \"Copenhagen\", id: 1 }");realm.commitTransaction();// Insert multiple items using a InputStreamInputStreamis=newFileInputStream(newFile("path_to_file"));realm.beginTransaction();try{realm.createAllFromJson(City.class,is);realm.commitTransaction();}catch(IOExceptione){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

Change listeners only work on Looper threads. For non-looper threads, you manually have to use Realm.refresh() instead.

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):

publicclassMyActivityextendsActivity{privateRealmrealm;// A reference to RealmChangeListener needs to be held to avoid being// removed by the garbage collector.privateRealmChangeListenerrealmListener;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);realm=Realm.getDefaultInstance();reamlListener=newRealmChangeListener(){@OverridepublicvoidonChange(){// ... do something with the updates (UI, etc.) ...}};realm.addChangeListener(realmListener);}@OverrideprotectedvoidonDestroy(){super.onDestroy();// Remove the listener.realm.removeChangeListener(realmListener);// Close the realm instance.realm.close();}}

You can easily remove all listeners when needed:

realm.removeAllChangeListeners();

Listeners are not limited to Realms. Listeners can also be attached to RealmObject instances as well as RealmResults instances. This allows you to react to changes to your objects and query results. Furthermore, when a change listener is called the object/result is automatically updated - there is no need to refresh the object.

publicclassMyActivityextendsActivity{privateRealmrealm;privateRealmChangeListenerpuppiesListener;privateRealmChangeListenerdogListener;privateRealmResults<Dog>puppies;privateDogdog;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);realm=Realm.getDefaultInstance();puppiesListener=newRealmChangeListener(){@OverridepublicvoidonChange(){// ... do something with the updated puppies instance}};// Find all the puppiespuppies=realm.where(Dog.class).lessThanOrEqualTo("age",2).findAll();puppies.addChangeListener(puppiesListener);dogListener=newRealmChangeListener(){@OverridepublicvoidonChange(){// ... do something with the updated Dog instance}};dog=realm.where(Dog.class).equals("name","Fido").findFirst();dog.addChangeListener(dogListener);}@OverrideprotectedvoidonDestroy(){super.onDestroy();// Remove the listenerspuppies.removeChangeListener(puppiesListener);dog.removeChangeListener(dogListener);// Close the realm instance.realm.close();}}

Lastly, typed-based change listeners will get notified when their referenced types change. Please see the example below.

Personperson=realm.where(Person.class).findFirst();person.getDogs();// => 2 - Assume there are 2 dogs in the listperson.addChangeListener(newRealmChangeListener(){@OverridepublicvoidonChange(){// React to the change in the Person instance.// This will also get called when any referenced dogs are updated.}});Dogdog=person.getDogs().get(0);realm.beginTransaction();dog.setAge(5);realm.commitTransaction();// Person change listener is called on the next iteration of the run loop because// a referenced dog object changed.

Migrations

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 the schema is as easy as changing the interface of the corresponding RealmObject subclass.

If you have no data stored on disk under the old database schema, just changing your code to the new definition will work fine. 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. This can be avoided by setting the schema version and migration code in RealmConfiguration.

RealmConfigurationconfig=newRealmConfiguration.Builder(context).schemaVersion(2)// Must be bumped when the schema changes.migration(newMyMigration())// 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.

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 (64 bytes) to RealmConfiguration.Builder.encryptionKey():

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.

Working With Android

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.

Adapter

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

To use RealmBaseAdapter, you need to add extra dependencies to application level build.gradle.

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

Intents

Since you cannot pass RealmObjects directly we advocate that you pass an identifier of the object you’re working with. A prime example would be if an object has a primary key. Pass that primary key value through an Intent via the extras bundle:

// Assuming we had a person class with a @PrimaryKey on the 'id' field ...Intentintent=newIntent(getActivity(),ReceivingService.class);intent.putExtra("person_id",person.getId());getActivity().startService(intent);

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

// in onCreate(), onHandleIntent(), etc.StringpersonId=intent.getStringExtra("person_id");Realmrealm=Realm.getDefaultInstance();Personperson=realm.where(Person.class).equalTo("id",personId).findFirst();// do something with the person ...realm.close();

Full working examples can be found in the Object Passing portion of the threading example. The example shows you how to pass id’s and retrieve the RealmObject in very common Android use cases.

Strategies When Dealing With Android Framework Threads

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.

privateclassDownloadOrdersextendsAsyncTask<Void,Void,Long>{protectedLongdoInBackground(Void...voids){// Now in a background thread.// Open the RealmRealmrealm=Realm.getDefaultInstance();// Work with Realmrealm.createAllFromJson(Order.class,api.getNewOrders());OrderfirstOrder=realm.where(Order.class).findFirst();longorderId=firstOrder.getId();// Id of orderrealm.close();returnorderId;}protectedvoidonPostExecute(LongorderId){// Back on the Android mainThread// do something with orderId such as query Realm// for the order and perform some operation with it.}}

IntentService

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

publicclassOrdersIntentServiceextendsIntentService{publicOrdersIntentService(Stringname){super("OrdersIntentService");}@OverrideprotectedvoidonHandleIntent(Intentintent){// Now in a background thread.// Open the RealmRealmrealm=Realm.getDefaultInstance();// Work with Realmrealm.createAllFromJson(Order.class,api.getNewOrders());OrderfirstOrder=realm.where(Order.class).findFirst();longorderId=firstOrder.getId();// Id of orderrealm.close();}}

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 classpublicclassUserextendsRealmObject{privateStringname;privateStringemail;// getters and setters left out ...}Gsongson=newGsonBuilder().create();Stringjson="{ name : 'John', email : '[email protected]' }";Useruser=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.

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.

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:

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.

Jackson-databind

Jackson uses reflection to perform the databinding. This conflicts with Realm’s support for RxJava as RxJava might not be available to the class loader. This can result in an exception that looks like this:

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.

@SubscribepublicvoidhandleEvent(OttoEventevent){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})publicclassPersonextendsRealmObject{// ...}

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

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.

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.

GitHubServiceservice=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.

// Combining Realm, Retrofit and RxJava (Using Retrolambda syntax for brevity)// Load all persons and merge them with their latest stats from GitHub (if they have any)Realmrealm=Realm.getDefaultInstance();GitHubServiceapi=retrofit.create(GitHubService.class);realm.where(Person.class).isNotNull("username").findAllAsync().asObservable().filter(persons.isLoaded).flatMap(persons->Observable.from(persons)).flatMap(person->api.user(person.getGithubUserName()).observeOn(AndroidSchedulers.mainThread()).subscribe(user->showUser(user));

Please note, Asynchronous Queries are non blocking and the code above will immediately return a RealmResults instance. If you want to ensure you’re only operating on a loaded list you should filter the Observable via the filter operator and check the list by calling the RealmResults<E>.isLoaded() method. By checking to see if the RealmResults are loaded you can then determine if your query has completed or not.

Configuration

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:1.1.0'}

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

If no RxObservableFactory is defined, Realm defaults to RealmObservableFactory which is a class provided by Realm that supports RxJava <= 1.1.*.

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 you have 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 (more info). Adding a watch for any of the accessors will yield correct values. See the image below:

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{enableNdktrue}

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:

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.

The length of field names has a upper limit of 63 character.

Nested transactions are not supported, and an exception is thrown if they are detected.

Strings and byte arrays (byte[]) cannot be larger than 16 MB.

Sorting and querying on String

Sorting and 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). In addition, setting the case insensitive flag in queries 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. The thread example shows how to use Realm in a multithreading environment. Read more about Realm’s threading.

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.

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 be neither used as a key in HashMap nor saved in HashSet.

Best Practices

Preventing Application Not Responding Errors (ANR’s)

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 Java memory manager. Java 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 ApplicationpublicclassMyApplicationextendsApplication{@OverridepublicvoidonCreate(){super.onCreate();RealmConfigurationrealmConfiguration=newRealmConfiguration.Builder(this).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.publicclassMyActivityextendsActivity{privateRealmrealm;privateRecyclerViewrecyclerView;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);realm=Realm.getDefaultInstance();setContentView(R.layout.activity_main);recyclerView=(RecyclerView)findViewById(R.id.recycler_view);recyclerView.setAdapter(newMyRecyclerViewAdapter(this,realm.where(MyModel.class).findAllAsync()));// ...}@OverrideprotectedvoidonDestroy(){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.publicclassMyFragmentextendsFragment{privateRealmrealm;privateRecyclerViewrecyclerView;@OverridepublicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,BundlesavedInstanceState){realm=Realm.getDefaultInstance();Viewroot=inflater.inflate(R.layout.fragment_view,container,false);recyclerView=(RecyclerView)root.findViewById(R.id.recycler_view);recyclerView.setAdapter(newMyRecyclerViewAdapter(getActivity(),realm.where(MyModel.class).findAllAsync()));// ...returnroot;}@OverridepublicvoidonDestroyView(){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 RealmChangedListener. The objects are already updated and ready to be redrawn on the screen.

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.

FAQ

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

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.

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:

Should I use Realm in production applications?

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. 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 for any reason 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 the IDE 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.

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, accessing the Realm file might leave your Realm file in a corrupted or an 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.)

Encryption is not supported on this device Exception

Realm’s encryption implementation used to rely on signal handler. But a few older devices (HTC One X for example) does not work correctly with signal handlers. From v0.82.2 Realm tried to detect if the device had this problem when opened the encrypted Realm, and threw a RealmEncryptionNotSupportedException on those devices.

From v0.85.0 Realm’s encryption implementation has been changed to another solution which supports all kinds of devices. So RealmEncryptionNotSupportedException is not needed and has been removed from v0.85.0.

I see a network call to Mixpanel when I run my app, what is that?

Realm collects anonymous analytics when you run the Realm annotation processor 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 in production, or running on your user’s devices — only when your source code is annotated. 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.