Realm Mobile Platform: Offline-first TaskManager app – basics of Realm

In this part of the series we are going to focus on implementing basic Realm support to the TaskManager app by using Realm Mobile Database.

Part 4: Coming soon

Here you can read the opening article of the series, devoted to defining the technology stack and the UI of the app. At the end of the series you will know how to build offline-first TaskManager app with realtime synchronization.

1. Setup

Firstly, we will need to update our gradle build to fetch Realm library.

Project build.gradle

And apply it to the app’s build.gradle

App’s build.gradle

Read Installing Realm for Android: Why is it Changing? if you are wondering why Realm is provided as a plugin, and not as a standard dependency.

Now we can proceed and initialize our Realm with init(Context) method.
According to the documentation, the best place to do that is the onCreate method of Application class.

We also need to update the AndroidManifest.xml file

2. Mocking Tasks

Before adding anything to Realm, we need to set its configuration. In this case we will simply use the default option. By doing that Realm will create a file called “default.realm” saved in Context.getFilesDir().

Realm is now set and ready. We can define our mock tasks.

One thing, however, is still missing here. In order for this code to work, our Task model must extend RealmObject class (all models managed by Realm have to do that) and have a default constructor.

3. Loading tasks

To load the tasks we will use a where query.

Please note that this could also be achieved with rxjava (yes, realm supports it!), however, for the sake of simplicity we will stick to the easiest solution.


4. Adding & Removing tasks

In this part, we are going to add the feature that adds and then removes tasks from the TaskManager app (removal will be done by swipe gesture).

The implementation of the gesture listener (SwipeToDismissTouchListener) can be found in this github project DynamicRecyclerView

As you can see these two operations are really straightforward.


5. Updating tasks

Implementation of tasks updates will be kept as simple as possible.
To do that let’s define TaskCompletedListener interface in TaskRowHolder class which will be implemented by the MainActivity.

Next, we need to update the TaskAdapter class.

Finally, handling the update by MainActivity.

As you can see,  we update tasks the same way as we run any other operation in this tutorial (by invoking Realm logic within the Transaction body).


6. Tasks order

To make sure that our tasks are ordered properly we are going to introduce a new field createdAt

Update the addTaskToRealm method of MainActivity.

And finally use it with Realm sort method to get a properly sorted list of tasks!

Final Result

Now that everything is in place, we are free to remove the code mocking our tasks.

7. Things worth remembering from the documentation

  • Every model which is stored in Realm Mobile database must extend the RealmObject class. An alternative to extending the RealmObject base class is implementing the RealmModel interface and adding the @RealmClass annotation.
  • Realm supports the following types: boolean, byte, short, int, long, float, double, String, Date, byte[], Boolean, Byte, Short, Integer, Long, Float and Double (boxed types can be set to null). Types byte, short, int, and long are all mapped to long within Realm.
  • Annotations:
    • @Ignore – field annotated with @Ignore won’t be persisted to disk
    • @Index – the annotation adding a search index to the field. This one makes inserts slow but gets queries faster
    • @PrimaryKey – adding a primary key to an object. Compound keys (with multiple fields) are not supported
  • Realm supports many-to-one and many-to-many relationships
  • All write operations (adding, modifying, and removing objects) must be done within transaction blocks
  • Reading data from realm is not blocked by write transactions
  • It’s impossible to update one element of a string or byte arrays. If you want to do that, you will have to alter the element in the array, and then assign this array again to chosen field
  • Supported query conditions:
    • between(), greaterThan(), lessThan(), greaterThanOrEqualTo() & lessThanOrEqualTo()
    • equalTo() & notEqualTo()
    • contains(), beginsWith() & endsWith()
    • isNull() & isNotNull()
    • isEmpty() & isNotEmpty()
  • 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 Realm opened inside a thread without a Looper will throw an IllegalStateException.
  • RealmConfiguration object is used to control all aspects of how a Realm is created.
  • It is important to remember to close your Realm instances when you are done with them.
  • Finding your Realm file
  • 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 other thread.
Subscribe to our newsletter