I am trying out Realm along with Android architecture components including LiveData.
I have been following Google's Guide to Application Architecture:
https://developer.android.com/topic/libraries/architecture/guide.html
...substituting Room with Realm.
I have everything working using:
LiveData<RealmResults<CustomModelObject>>
from my repository layer right through ViewModel to View.
I am thinking it might be nicer to only have more generic types coming back from repository so LiveData<List<CustomModelObject>>
rather than LiveData<RealmResults<CustomModelObject>>
.
Here is a code snippet of where I have got stuck:
@NonNull
@Override
protected LiveData<List<CustomModelObject>> loadFromDb() {
return Transformations.switchMap(customModelObjectsDao.getCustomModelObjects(),
new Function<RealmResults<CustomModelObject>, LiveData<List<CustomModelObject>>>() {
@Override
public LiveData<List<CustomModelObject>> apply(RealmResults<CustomModelObject> data) {
if (data == null) {
return AbsentLiveData.create();
} else {
return customModelObjectsDao.getCustomModelObjects();
}
}
});
}
customModelObjectsDao.getCustomModelObjects()
currently returns LiveData<RealmResults<Inspiration>>
.
I want to transform it to LiveData<List<Inspiration>>
.
I have tried various Transformations.map
and Transformations.switchMap
etc with no success and I think I have been staring at it too long now :)
Am I on the right path or am I missing something obvious?
Any help is greatly appreciated.
Thanks, Paul.
UPDATE
DAO:
public RealmLiveData<CustomModelObject> getCustomModelObjects() {
return asLiveData(realm.where(CustomModelObject.class).findAllAsync());
}
asLiveData Impl:
fun <T: RealmModel> RealmResults<T>.asLiveData() = RealmLiveData<T>(this)
fun Realm.CustomModelObjectsDao(): CustomModelObjectsDao = CustomModelObjectsDao(this)
UPDATE 2
public class RealmLiveData<T> 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);
}
}
In your case, replacing LiveData<RealmResults<T>
with LiveData<List<T>>
would be enough to solve your problem.
However, I'd advise trying out the RealmLiveResults
class that is available in the official example:
/**
* This class represents a RealmResults wrapped inside a LiveData.
*
* Realm will always keep the RealmResults up-to-date whenever a change occurs on any thread,
* and when that happens, the observer will be notified.
*
* The RealmResults will be observed until it is invalidated - meaning all local Realm instances on this thread are closed.
*
* @param <T> the type of the RealmModel
*/
public class LiveRealmResults<T extends RealmModel> extends LiveData<List<T>> {
private final RealmResults<T> results;
// The listener will notify the observers whenever a change occurs.
// The results are modified in change. This could be expanded to also return the change set in a pair.
private OrderedRealmCollectionChangeListener<RealmResults<T>> listener = new OrderedRealmCollectionChangeListener<RealmResults<T>>() {
@Override
public void onChange(@NonNull RealmResults<T> results, @Nullable OrderedCollectionChangeSet changeSet) {
LiveRealmResults.this.setValue(results);
}
};
@MainThread
public LiveRealmResults(@NonNull RealmResults<T> results) {
//noinspection ConstantConditions
if (results == null) {
throw new IllegalArgumentException("Results cannot be null!");
}
if (!results.isValid()) {
throw new IllegalArgumentException("The provided RealmResults is no longer valid, the Realm instance it belongs to is closed. It can no longer be observed for changes.");
}
this.results = results;
if (results.isLoaded()) {
// we should not notify observers when results aren't ready yet (async query).
// however, synchronous query should be set explicitly.
setValue(results);
}
}
// We should start observing and stop observing, depending on whether we have observers.
/**
* Starts observing the RealmResults, if it is still valid.
*/
@Override
protected void onActive() {
super.onActive();
if (results.isValid()) { // invalidated results can no longer be observed.
results.addChangeListener(listener);
}
}
/**
* Stops observing the RealmResults.
*/
@Override
protected void onInactive() {
super.onInactive();
if (results.isValid()) {
results.removeChangeListener(listener);
}
}
}
This way your dao
can expose LiveData<List<T>>
, and your Transformations.map()
should work.
来源:https://stackoverflow.com/questions/49654211/using-realm-and-livedata-converting-livedatarealmresultscustommodelobject-t