-
-
Save cmelchior/3fe791f84db37fd3bcb3749d4188168a to your computer and use it in GitHub Desktop.
/** | |
* Class connecting the Realm lifecycle to that of LiveData objects. | |
* Realm will remain open for as long as any LiveData objects are being observed. | |
*/ | |
abstract class LiveRealmData<T: RealmModel>(val config: RealmConfiguration) : LiveData<RealmResults<T>>() { | |
private val listener = RealmChangeListener<RealmResults<T>> { results -> value = results } | |
private lateinit var realm: Realm | |
private var results: RealmResults<T>? = null | |
override final fun onActive() { | |
realm = Realm.getInstance(config) | |
results = runQuery(realm); | |
results.addChangeListener(listener) | |
value = results; | |
} | |
override final fun onInactive() { | |
results!!.removeAllChangeListeners() | |
results = null | |
realm.close() | |
} | |
abstract fun runQuery(realm: Realm): RealmResults<T> | |
} | |
fun usage() : LiveData<RealmResults<Person>> { | |
return object: LiveRealmData<Person>(getConfig()) { | |
override fun runQuery(realm: Realm): RealmResults<Person> { | |
// Called on UI thread | |
return realm.where(Person::class.java).findAllAsync() | |
} | |
} | |
} |
👍
I think this might work better.
public class LiveRealmData<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 LiveRealmData(RealmResults realmResults) {
results = realmResults;
}
@Override
protected void onActive() {
results.addChangeListener(listener);
}
@Override
protected void onInactive() {
results.removeChangeListener(listener);
}
}
With the caller passing the realm instance in because the onActive onInactive fires on rotation. I think we don't want to re-run the query and close/open Realm each time. Just start/stop observing data changes.
public LiveRealmData<Loan> findLoansByNameAfter(final String userName, final Date after) {
return asLiveData(mRealm.where(Loan.class)
.like("user.name", userName)
.greaterThan("endTime", after)
.findAllAsync());
}
And Kotlin for the glue, so that it's available directly on RealmResults from kotlin.
fun <T:RealmModel> RealmResults<T>.asLiveData() = LiveRealmData<T>(this)
Yes, if you only use async
queries, that will work as well. The ViewModel becomes responsible for the Realm
lifecycle, but neither looks wrong to me. If the ViewModel uses the Realm for other things (which is probably likely), then your approach looks cleaner.
You can then argue if you should call setValue()
with the unloaded RealmResults
in the constructor or not. Bot have their use cases I guess.
public LiveRealmData(RealmResults realmResults) {
results = realmResults;
setValue(results);
}
setValue() should be called in the constructor.
@suryachintu + 1
Yup, that looks correct.