Sign in Go Pro

Realm & Android Architecture Components

How to Abstract Realm Completely from Activities and Fragments

This lesson is for PRO members.

Upgrade today to get access to all the PRO lessons.

Unlock this lesson
Autoplay

Up next

Previous

About

Description

The combination of LiveData, LiveData Transformations, and Interfaces, allows you to abstract your Realm domain model and database in a way that was not previously possible. This lesson will teach you how to use LiveData with Transformations and Realm effectively, so that you can abstract your Realm data models entirely from your Activities and Fragments.

Summary of Content (what you will learn):

  • How to expose LiveData<List<? extends Model>> from your DAOs, where Model is
    • A Read Only view of your data.
    • Database Agnostic - No ties to Realm or your underlying data model entities.
    • An interface that can easily be mocked for testing.

Additional Materials

Comments

How would you go about implementing a RecyclerView adapter that supports animations (essentially supporting notifyItemRange operations) that still keeps Realm/RealmResults abstracted away in the Repo/DAO layer? There is a realm-android-adapters project that offers the functionality, but you have to bleed in RealmResults in the UI layer.

Hi Tudor. You would need to use DiffUtil and identify manually which items have changed.

You may also want to take a look at a project called Realm Helpers, by Gabor Varadi. He has created some helpers and samples to show how to use Realm with a PagedListAdapter in a generic way too.

Hi Eric, thanks for the quick reply!

I was just looking at Gabor's repos. I discovered his monarchy lib with a good sample for the pagination lib.

My use case involves a long list of "conversations/messages" (it could have 2-3k+ items) that can change, be deleted, etc. I've written a small prototype with Realm (Monarchy lib) and the pagination library to download the data in steps when the user scrolls through.
I'm not super comfortable with the idea of detaching 3k+ items from realm and running a diff on that (through PagedListAdapter) every time something changes. Bleeding Realm into the UI and using its OrderedCollectionChangeSet might be a more CPU/battery friendly approach. Any thoughts on that?

Thanks!

Hi Tudor. You're welcome! :-) . Sorry this one took a bit longer..

I think you're spot on! Using a RealmAdapter and OrderedCollectionChangeSet, is probably better for your use case (if you can accept exposing RealmResults to your UI layer.). The clear advantage here is that nothing is copied into memory except the property data on your model as you access it to populate your ItemView. This would remain efficient even if your users scrolled through all 3k messages.

Monarchy with Paging should address the situation of efficiently handling all 3k records, loading only one page of records into memory at a time. However as you pointed out, if your user scrolls through 3k+ items eventually you'll have that many detached objects to diff. Monarchy w/ Paging or your own abstraction in an RecyclerView.Adapter would work well for casually scrolling through a large list of items, but not at the level you've described.

Hi, Eric! I like the idea of decoupling Realm dependency from UI layer by introducing additional interface. It is indeed easier to test later and so on.

I created the

@RealmClass
open class ExpenseTypeEntity(
@PrimaryKey var id: Int = 0,
var iconResourceId: Long = 0,
@Index var priority: Int = 0
) : RealmObject(), ExpenseType

and interface

interface ExpenseType {
fun getId():Int
fun getIconResourceId() : Long
fun getPriority() : Int
}

Of course, I get an error "class ExpenseTypeEntity is not abstract and does not implement public final fun getId()".

This means that I should probably put getters and setters in my RealmObjects, which is not Kotlin way. What would be the "right" Kotlin way in your opinion?

Best,
Drasko

Hi Drasko,

Try updating your Kotlin interface to:


interface ExpenseType {
val id: Int
val iconResourceId: Long
val priority: Int
}

and update your ExpenseTypeEntity to:


@RealmClass
open class ExpenseTypeEntity(
override @PrimaryKey var id: Int = 0,
override var iconResourceId: Long = 0,
override @Index var priority: Int = 0
) : RealmObject(), ExpenseType

In this case, the Kotlin interface is declaring that any implementer must supply a read only property for id, iconResourceId, and priority.

Thank you so much! I am new to Kotlin and am just amazed how things are simpler, simpler to the point that sometimes is hard to get use to them. :)

Agree, Kotlin is awesome! :-)

Hi Eric,

I have one more question regarding decoupling discussed in this lesson. It is very usual situation where instance of one RealmObject is an instance of another. Let's say that we also have class ExpenseEntity that has a member of type ExpenseTypeEntity from previous question and ExpenseTypeEntity implements ExpenseType.

@RealmClass
open class ExpenseEntity(
@PrimaryKey override var id: Long = 0,
//...
override var expenseType: ExpenseTypeEntity
) : RealmObject(), Expense

How can I create interface Expense? Should I change the way I presented class ExpenseEntity?

I tried something like:

interface Expense {
val id: Long
//...
val expenseType: ExpenseType
}

but I cannot build the app.
Thanks in advance!

>
You need to go PRO to post comments.

Lessons in Realm & Android Architecture Components