How to use LiveData with Realm

If you’re an Android Developer and haven’t been living under a rock since Google IO’17 you’ve undoubtedly seen a lot of excitement and numerous blog posts regarding Android Architecture Components.

There is indeed a lot to be excited about regarding the power and utility of these new components (ViewModel, Lifecycle, LiveData and Room).

Live Data Streams

From my perspective, LiveData is the most exciting part of the line up. It’s awesome to see Google now embracing the concept of live, auto-updating, data. It’s equally awesome to see how they’ve integrated LiveData right into the new SQLite ORM (Room).

This makes it easy to see the power of LiveData right away, but what I love most about the design of LiveData is that Google has made it generic and open for developers to use LiveData for a variety of other use cases such as:

Realm + LiveData

The flexible nature of LiveData allows it to be easily integrated into other 3rd party libraries too! As an engineer at Realm, this is very exciting for me because it means that I can wrap RealmResults as LiveData and use it as I would any other piece of LiveData.

This has at least two additional benefits.

It makes it even easier for developers to react to data changes as they no longer have to register a changeListener for RealmResults in their Activities onStart() method and unregister it onStop(). Rather this can happen automatically with Realm-LiveData when the owning Activity starts and stops observing it.

The second benefit is that it allows RealmResults to participate in LiveData Transformations. Transformations are great because they allow you to transform any LiveData from something very specific, like LiveData<RealmModel>, at your Repository or ViewModel layer, to something completely agnostic of the underlying source, like LiveData<String> at the Activity Layer. You get this without giving up the Live Auto-Updating nature of Realm. This keeps the various layers of your app isolated, which makes them easier to compose, update and test.

Getting Started

For a complete how-to guide and sample project on how to integrate Architecture Components into Realm, check out this other post I wrote, but this quick example should give you the general idea to get started.

1. Create a LiveData wrapper for your RealmResults.

// This works for results of any RealmModel in your project
public class RealmLiveData<T extends RealmModel> extends LiveData<RealmResults<T>> {
private RealmResults<T> results;
private final RealmChangeListener<RealmResults<T>> listener =
new RealmChangeListener<RealmResults<T>>() {
@Override
public void onChange(RealmResults<T> results) {
setValue(results);
}
};
    public RealmLiveData(RealmResults<T> realmResults) {
results = realmResults;
}
    @Override
protected void onActive() {
results.addChangeListener(listener);
}
    @Override
protected void onInactive() {
results.removeChangeListener(listener);
}
}

2. Use that to wrap RealmResults exposed from your Realm Dao or Repository layer.

public RealmLiveData<Loan> findLoansByNameAfter(String userName, Date after) {
return asLiveData(realm.where(Loan.class)
.like("user.name", userName)
.greaterThan("endTime", after)
.findAllAsync());
// Async runs the fetch off the main thread, and returns
// results as LiveData back on the main.

}

3. Finally, use it as you would any other LiveData in your ViewModel, mapping it to something more generic for your Activity layer, and subscribe to it from your Activity.

// ViewModel
public class LoanViewModel extends ViewModel {
    private Realm realm;

public LiveData<String> loans;
// Activity Subscribed to LiveData<String>
    private void subscribeToMikesLoansSinceYesterday() {
RealmLiveData<Loan> loans = loanDao(realm)
.findLoansByNameAfter("Mike", getYesterdayDate());
        loans = Transformations.map(loans, new Function() {...});
}
...
}
// Activity
public class LoanActivity extends LifecycleActivity {

protected void onCreate(Bundle savedInstanceState) {
...
viewModel.loans.observe(this, new Observer<String>() {
public void onChanged(String result) {
updateUI(result)
}
});
...
}
...
}

4. (Optionally) Sprinkle in a little bit of Kotlin and it’s as if Android Architecture Components have been there the entire time! 🎩

// Use as
// realm.loanDao() in Kotlin
// loanDao(realm) in Java
fun Realm.loanDao(): LoanDao = LoanDao(this)
// Use as
// realmResults.asLiveData() in Kotlin
// new RealmLiveData(realm) in Java
fun <T:RealmModel> RealmResults<T>.asLiveData() = RealmLiveData<T>(this)

Impact of Architecture Components

What this means for developers who love Realm for its simple API, rich notification system and real time data synchronization across devices, is that all of the great parts of Android Architecture Components, ViewModels, Lifecycle, LiveData and even encapsulated data access through DAOs are available without giving up the features they’ve grown to love! ❤️