使用领域和 LiveData。将 LiveData<RealmResults<CustomModelObject>> 转换为 LiveData<List<CustomModelObject>>

Using Realm and LiveData. Converting LiveData<RealmResults<CustomModelObject>> to LiveData<List<CustomModelObject>>

我正在试用 Realm 以及 Android 架构组件,包括 LiveData。

我一直在关注 Google 的应用程序架构指南:

https://developer.android.com/topic/libraries/architecture/guide.html

...将 Room 替换为 Realm。

我的一切都在使用:

LiveData<RealmResults<CustomModelObject>>

从我的存储库层直接通过 ViewModel 到 View。

我认为从存储库返回更多通用类型可能会更好,因此 LiveData<List<CustomModelObject>> 而不是 LiveData<RealmResults<CustomModelObject>>

这是我遇到问题的代码片段:

@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() 当前 returns LiveData<RealmResults<Inspiration>>.

我想将其转换为LiveData<List<Inspiration>>

我尝试了各种 Transformations.mapTransformations.switchMap 等等,但都没有成功,我想我现在已经盯着它看太久了:)

我是在正确的道路上还是遗漏了一些明显的东西?

非常感谢任何帮助。

谢谢, 保罗.

更新

DAO:

public RealmLiveData<CustomModelObject> getCustomModelObjects() {
    return asLiveData(realm.where(CustomModelObject.class).findAllAsync());
}

asLiveData 实现:

fun <T: RealmModel> RealmResults<T>.asLiveData() = RealmLiveData<T>(this)
fun Realm.CustomModelObjectsDao(): CustomModelObjectsDao = CustomModelObjectsDao(this)

更新 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);
}
}

对于您的情况,将 LiveData<RealmResults<T> 替换为 LiveData<List<T>> 就足以解决您的问题。

不过,我建议您尝试 RealmLiveResults class 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);
        }
    }
}

这样你的 dao 可以公开 LiveData<List<T>>,你的 Transformations.map() 应该可以工作。

如果你需要:

val list : LiveData<List<mRealmObject>>

首先:创建这个文件:

class RealmLiveData<T : RealmModel>(private val results: RealmResults<T>) :
  LiveData<RealmResults<T>>() {
  private val listener: RealmChangeListener<RealmResults<T>> =
    RealmChangeListener { results -> value = results }

  override fun onActive() {
    results.addChangeListener(listener)
  }

  override fun onInactive() {
    results.removeChangeListener(listener)
  }
}

fun <T: RealmModel> RealmResults<T>.asLiveData() = RealmLiveData<T>(this)

第二:获取新的 RealmLiveData :

val mRealmLiveData = realm.where(mRealmObject::class.java).findAllAsync().asLiveData()

最后,像这样获取您需要的列表:

val list: LiveData<List<mRealmObject>> = Transformations.map(mRealmLiveData) {
  realmResult ->
    realm.copyFromRealm(realmResult)
  }

如果在 ViewModel 中使用它:

//get realm instance   
val realm: Realm by lazy {
        Realm.getDefaultInstance()
    }
// get your live data
val list: LiveData<List<mRealmObject>> = Transformations.map(mRealmLiveData) {
  realmResult ->
    realm.copyFromRealm(realmResult)
  }
// Close your realm instance onCleraded
override fun onCleared() {
  realm.close()
  super.onCleared()
  }