【问题标题】:Using Realm and LiveData. Converting LiveData<RealmResults<CustomModelObject>> to LiveData<List<CustomModelObject>>使用领域和 LiveData。将 LiveData<RealmResults<CustomModelObject>> 转换为 LiveData<List<CustomModelObject>>
【发布时间】:2018-04-04 14:54:42
【问题描述】:

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

我一直在遵循 Google 的应用程序架构指南:

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

...用 Realm 代替 Room。

我的一切都在使用:

LiveData<RealmResults<CustomModelObject>>

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

我认为从存储库返回更多泛型类型可能会更好,所以LiveData&lt;List&lt;CustomModelObject&gt;&gt; 而不是LiveData&lt;RealmResults&lt;CustomModelObject&gt;&gt;。

这是我卡住的代码sn-p:

@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() 当前返回LiveData&lt;RealmResults&lt;Inspiration&gt;&gt;。

我想把它转换成LiveData&lt;List&lt;Inspiration&gt;&gt;。

我尝试了各种Transformations.map 和Transformations.switchMap 等都没有成功,我想我已经盯着它太久了:)

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

非常感谢任何帮助。

谢谢, 保罗。

更新

道:

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

【问题讨论】:

  • 我需要知道你的 DAO 如何回答这个问题 (customModelObjectsDao.getCustomModelObjects())
  • 嗨 Epic,我已经更新了这个问题。谢谢,保罗。
  • Welp,现在我需要询问RealmLiveData 是否是自定义的,还是from the realm-examples :D 但我认为您还需要在问题中添加RealmLIveData 以使其完整
  • 哈!我认为这即将到来:) 它几乎与更少的错误处理相同。谢谢,保罗。

标签: android realm android-livedata


【解决方案1】:

在您的情况下,将 LiveData&lt;RealmResults&lt;T&gt; 替换为 LiveData&lt;List&lt;T&gt;&gt; 就足以解决您的问题。

但是,我建议尝试the official example 中提供的RealmLiveResults 类:

/**
 * 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&lt;List&lt;T&gt;&gt;,你的Transformations.map() 应该可以工作。

【讨论】:

  • 我是个菜鸟 :) 你帮了我很大的忙,谢谢!我尝试了你的第一个建议,它立即奏效。我还将听取您的建议并使用官方示例中的 livedata 包装器。干杯,保罗。
  • 我听说有人说在onActive() 中缺少setValue(results) 调用。我无法验证也无法反驳这一说法。我不认为它应该,假设您使用的是observe,然后结果发生了变化,但谁知道呢。
【解决方案2】:

如果您需要:

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()
  }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多