A couple of reasons why you should consider using Realm
- Very little coding makes Realm easy to set up and easy to use
- Fast queries taking nanoseconds
- Safe threading so you can access the same data at the same time from multiple threads
- Use the same Realm for all your apps, on any major platform
- Secure your data with transparent encryption and decryption
- Reactive architecture, meaning you can connect your User Interface to your Realm and data changes will appear automatically, so you will always have the latest data
- Realm provides utility classes to help you bind your data to list views as well as recycler views
- Build your local realm database and then connect it to the Realm Mobile Platform to sync your data across all connected devices
- Add your json objects directly into Realm
- Over 1 billion users rely on Realm
What do you need to use Realm in your apps?
- Android Studio >= 1.5.1
- A recent version of the Android SDK
- JDK version >=7
- Realm supports Android from API Level 9 (Android 2.3 Gingerbread) and above
Getting started
It’s easy setting up Realm.
Setting up the dependency and plugin
- Add the class path dependency to the project level build.gradle file:
Add the class path dependency to the project level build.gradle file
- Apply the realm-android plugin to the top of the application level build.gradle file
Apply the realm-android plugin to the top of the application level build.gradle file
Initialise Realm
You would usually initialise Realm in your application subclass’s onCreate():
Initialise Realm in your application
You’re now ready to use Realm!
Configuring a Realm
You can configure Realm to suite your needs (see the documentation) or simply use the default configuration. We’ll use the default configuration in our tutorial app.
Get your Realm instance
You need to get a realm instance which you keep as long as you need to access your data. Don’t forget to close the Realm when you no longer need to access the data.
We get a Realm instance in our activity’s onCreate() method and close the instance in the activity’s onDestroy() method.
You store Realm Objects in the Realm
Realm Models
Create your object classes and turn them into realm objects by extending the RealmObject class. You then interact with the RealmObject which is a live representation of the data. Modifying this object is immediately reflected wherever a query result is used.
Writing data to the realm
You must wrap any write operation in a write transaction. This ensures that your data will always be in a consistent state as the write transaction is either committed or cancelled.
All changes are written to disk during the commit which will only succeed if all of the changes can be persisted.
Cancelling a transaction discards any changes.
Write transactions block each other so rather use the asynchronous transaction if you are going to be writing data on the UI and in the background at the same time. The asynchronous transaction will run its transaction on a background thread and report back when the transaction is done.
When you commit a write transaction to a Realm, all other instances of that Realm will be notified and automatically updated.
Crash safe
If there is a problem during the transaction and an exception is thrown, the data in the transaction is lost but the Realm is not affected. However if the exception is caught, you should cancel the transaction. This is done automatically if you use exceuteTansaction().
Creating your objects
RealmObjects are strongly tied to a Realm so it is advisable to create them through the Realm. This means that you can then use the newly created RealmObject and it will always reflect the latest data.
Alternatively you can first create the object and then add it later. In this case, if you change the original data object, the change will not be reflected by the returned RealmObject.
Queries: Reading data
Most queries are fast enough to be run on the main thread.
Data is not copied during a Realm read, instead, a reference to the original object is returned.
Queries return a RealmResults object containing a reference to the original object, you then work with the original object.
RealmResults behave similarly to Java’s AbstractList so an empty result returns 0, the size of the list and not null.
Auto-Updating Results
RealmResults contain live data so never have to be re-fetched. Modifying the original objects that affect the query will automatically update the RealmResults object.
Note that because the RealmResults object is auto-updating, you should not rely on counts and indices remaining constant.
Retrieving objects by type
It makes sense to use your RealmObjects type as the basis for your queries. We’ll be using our Contact class type in our tutorial app.
Looping through the results
The RealmResults is iterable so you can loop through it using an iterator or the traditional for loop.
Deletion
You can delete the results of a query from the Realm but you must do so in a write transaction. We’ll show you how later when we discuss the tutorial app.
Asynchronous Queries
You may want to run complex queries on a background thread.
The query immediately returns a RealmResults object which is updated once the query is complete. You can also use a RealmChangeListener which will be called every time the RealmResults are updated to reflect the latest changes in the Realm (usually after a commit).
Our Tutorial using the Realm Mobile Database
What does our tutorial app do?
We demonstrate how to use Realm to save a list of contact details in a Realm. We also show you how to:
- Query the Realm to get all the contacts
- Add a new contact to the Realm
- Delete a single contact in the Realm
- Update a single contact in the Realm
- Delete all the contacts in the Realm
Our dummy data
We created a json file containing our dummy contacts data and stored it in our app’s assets folder.
The object of the Realm: Our Contact Model
Our Contact class extends the RealmObject class. We can then create our contact objects within a Realm, using our object class.
Each contact has the following fields:
- name – a string
- telephone – an int
- sex –a string
- country – a string
You can use a json editor like this one http://www.jsonin.com/jsoneditoronline/ to create your json file.
Our application class: MyApplication
We call Realm.init() in our application class to initialise the Realm library and to create a default configuration that we can use in our activity.
The activity: MyRealmActivity
We have one activity where everything happens.
Laying out our Realm: Our layout
The activity’s layout contains a number of buttons to perform the following:
- load all the dummy data into the database
- get and display all the data
- add a contact to the database
- delete a contact
- update a contact
- show the updated contact’s details
- delete all the items in the database
The methods handling the button clicks are in the activity.
Getting our Realm
We’ve initialised our Realm in our application class. We now get an instance of our Realm which we’ll use to interact with to save and query data. We do this in our activity’s onCreate() method:
Get an instance of your Realm in the onCreate() method
Closing our Realm
You need to close the Realm instance when you’re finished using it. If you don’t, it could cause memory leaks and unnecessarily increase the size of your Realm file.
We close our Realm in the activity’s onDestroy() method, so it’s open while the activity is alive:
Close your Realm in the onDestroy() method
Entering our Realm: Using the database
We can interact with our Realm once we have initialised and obtained an instance of a Realm.
Loading the dummy data
Our dummy data is stored in a json file in the assets folder. We get the data out of the file and store it in a list, the contactsList.
Pressing the LOAD DATA button saves the list in our Realm:
Saving data in our Realm
So what’s happening here?
- beginTransaction() – starts a transaction . Transactions are used to automatically create, update and delete objects within a Realm. You must wrap all write operations in a write transaction. This ensures that your data is always in a consistent state as the write transaction is either committed or cancelled
- copyToRealm() - Copies our list of contacts to the Realm, returning a copy of the list. Realm will now only manage this returned copy of the list. Changes to the original list will not be persisted
- commitTransaction() - All changes since the call to Realm.beginTransaction() are persisted to disk. The Realm now returns to being read-only. All other Realm instances are notified that a change has occurred, and update their objects. Any RealmResults will reflect the changes from this commit
Displaying the dummy data
Pressing the GET ALL DATA button starts a query to find all the contacts in our Realm, displaying the results in the LogCat:
Querying our Realm
So what’s happening here?
- RealmQuery – holds the query that we want to perform on our Realm
- where – we get a typed query (for our Contact class) – we only want to query the Contact objects in our Realm
- RealmResults – holds a reference to all the matching objects for our query. It will never be null as it reflects a value returned by the size() method
- findAll() – finds all the objects matching our query condition (the Contact objects)
- for loop – we iterate through the results and display each contact’s name in the logCat
Adding a single contact
Press the ADD CONTACT button to add a single contact’s details to our Realm.
Add a contact to our Realm
So what’s happening here?
- beginTransaction() – starts a transaction . Transactions are used to automatically create, update and delete objects within a Realm. You must wrap all write operations in a write transaction. This ensures that your data is always in a consistent state as the write transaction is either committed or cancelled
- createObject() – creates and adds a new Contact object to our Realm
- getNewContact() – we get a new contact’s details. Note that we create the object within the transaction. We can now use this object and it will always reflect the latest data
- commitTransaction() - All changes since the call to Realm.beginTransaction() are persisted to disk. The Realm now returns to being read-only. All other Realm instances are notified that a change has occurred, and update their objects. Any RealmResults will reflect the changes from this commit
Deleting a single contact
Press the DELETE CONTACT button to delete a single contact from our Realm.
Delete a contact from our Realm
So what’s happening here?
- RealmQuery – holds the query that we want to perform on our Realm
- where – we get a typed query (for our Contact class) – we only want to query the Contact objects in our Realm
- equalTo() – we want to look for a contact where the name field matches “Jack"
- findFirst() – finds the first contact that satisfies our query condition
- if statement – we check whether we have found a contact matching our requirement
- executeTransaction() – executes the given transaction on our Realm. beginTransaction() and commitTransaction() are called automatically. If an exception is thrown during the transaction then cancelTransaction() will be called instead of commitTransaction()
- deleteFromRealm() - deletes the object from our Realm
- Toast – we show a toast if the contact we’re looking for does not exist
Updating a single contact
Press the UPDATE CONTACT button to update a contact’s details.
Updating a contact in our Realm
So what’s happening here?
- RealmQuery – holds the query that we want to perform on our Realm
- where – we get a typed query (for our Contact class) – we only want to query the Contact objects in our Realm
- equalTo() – we want to look for a contact where the name field matches “Peter"
- findFirst() – finds the first contact that satisfies our query condition
- if statement – we check whether we have found a contact matching our requirement
- executeTransaction() – executes the given transaction on our Realm. beginTransaction() and commitTransaction() are called automatically. If an exception is thrown during the transaction then cancelTransaction() will be called instead of commitTransaction()
- set the name and sex field of the matching contact
- Toast – we show a toast if the contact we’re looking for does not exist
Show the updated contact
Press the SHOW UPDATED CONTACT DETAILS button to show the updated contact’s details.
Query our Realm for a contact
So what’s happening here?
- RealmQuery – holds the query that we want to perform on our Realm
- where – we get a typed query (for our Contact class) – we only want to query the Contact objects in our Realm
- equalTo() – we want to look for a contact where the name field matches “Petronella"
- findFirst() – finds the first contact that satisfies our query condition
- if statement – we check whether we have found a contact matching our requirement
- we display the matching contact’s details in the LogCat
- Toast – we show a toast if the contact we’re looking for does not exist
Emptying our Realm: Deleting all the items in the database
We delete all the contacts from our Realm.
Delete all Contact data in our Realm
So what’s happening here?
- executeTransaction() – executes the given transaction on our Realm. beginTransaction() and commitTransaction() are called automatically. If an exception is thrown during the transaction then cancelTransaction() will be called instead of commitTransaction()
- delete() – we delete all the contact objects in our Realm
Here are some useful Realm links
I hope that you have found this tutorial useful, if you did, please consider buying me a cup of coffee to keep me awake!. Thanks.
Other means of saving data in your Android apps
You may also be interested in our Firebase Realtime Database tutorial
We also have a SQLite database tutorial, Using a SQLite database in Android
You can also save primitive data in a SharedPreference file, here’s a tutorial that will show you how: Using Android’s SharedPreferences to save persistent data: a practical example and tutorial
Download the project files here