android - 如何在后台线程上执行 LiveData 转换?

标签 android android-room android-architecture-components android-thread android-architecture-lifecycle

我需要转换一种类型的数据,由 LiveData 返回对象在后台线程中转化为另一种形式,以防止 UI 滞后。

在我的具体情况下,我有:

  • MyDBRow对象(由原始 longString 组成的 POJO);
  • 一个Room DAO通过 LiveData<List<MyDBRow>> 发射这些的实例;和
  • 一个期待更丰富的 UI MyRichObject对象(带有基元的 POJO 膨胀成例如 date/time objects )

所以我需要转换我的 LiveData<List<MyDBRow>>进入 LiveData<List<MyRichObject>> ,但不在 UI 线程上

Transformations.map(LiveData<X>, Function<X, Y>) 方法执行此所需的转换,但我不能使用它,因为它在主线程上执行转换:

Applies the given function on the main thread to each value emitted by source LiveData and returns LiveData, which emits resulting values.

The given function func will be executed on the main thread.

制作 LiveData 的干净方法是什么?发生转变:

  1. 在主线程之外的某个地方,以及
  2. 仅在需要时(即仅当某些东西正在观察预期的转换时)?

最佳答案

  • 原文,“来源” LiveData 可以通过新的 Observer 进行监控实例。
  • Observer实例,当来源LiveData发出后,可以准备一个后台线程来执行所需的转换,然后通过一个新的、“转换后的”LiveData 发出它。 .
  • 转换后的 LiveData可以附上前述的Observer到源LiveData当它有 Activity 时 Observer s,并在没有时分离它们,确保源 LiveData仅在必要时才被观察。

问题给出了例子来源LiveData<List<MyDBRow>>并且需要一个转换后的 LiveData<List<MyRichObject>> .组合转换 LiveDataObserver可能看起来像这样:

class MyRichObjectLiveData
        extends LiveData<List<MyRichObject>>
        implements Observer<List<MyDBRow>>
{
    @NonNull private LiveData<List<MyDBRow>> sourceLiveData;

    MyRichObjectLiveData(@NonNull LiveData<List<MyDBRow>> sourceLiveData) {
        this.sourceLiveData = sourceLiveData;
    }

    // only watch the source LiveData when something is observing this
    // transformed LiveData
    @Override protected void onActive()   { sourceLiveData.observeForever(this); }
    @Override protected void onInactive() { sourceLiveData.removeObserver(this); }

    // receive source LiveData emission
    @Override public void onChanged(@Nullable List<MyDBRow> dbRows) {
        // set up a background thread to complete the transformation
        AsyncTask.execute(new Runnable() {
            @Override public void run() {
                assert dbRows != null;
                List<MyRichObject> myRichObjects = new LinkedList<>();
                for (MyDBRow myDBRow : myDBRows) {
                    myRichObjects.add(MyRichObjectBuilder.from(myDBRow).build());
                }
                // use LiveData method postValue (rather than setValue) on
                // background threads
                postValue(myRichObjects);
            }
        });
    }
}

如果需要多个这样的转换,上面的逻辑可以像这样通用:

abstract class TransformedLiveData<Source, Transformed>
        extends LiveData<Transformed>
        implements Observer<Source>
{
    @Override protected void onActive()   { getSource().observeForever(this); }
    @Override protected void onInactive() { getSource().removeObserver(this); }

    @Override public void onChanged(@Nullable Source source) {
        AsyncTask.execute(new Runnable() {
            @Override public void run() {
                postValue(getTransformed(source));
            }
        });
    }

    protected abstract LiveData<Source> getSource();
    protected abstract Transformed getTransformed(Source source);
}

问题给出的示例的子类可能如下所示:

class MyRichObjectLiveData
        extends TransformedLiveData<List<MyDBRow>, List<MyRichObject>>
{
    @NonNull private LiveData<List<MyDBRow>> sourceLiveData;

    MyRichObjectLiveData(@NonNull LiveData<List<MyDBRow>> sourceLiveData) {
        this.sourceLiveData = sourceLiveData;
    }

    @Override protected LiveData<List<MyDBRow>> getSource() {
        return sourceLiveData;
    }

    @Override protected List<MyRichObject> getTransformed(List<MyDBRow> myDBRows) {
        List<MyRichObject> myRichObjects = new LinkedList<>();
        for (MyDBRow myDBRow : myDBRows) {
            myRichObjects.add(MyRichObjectBuilder.from(myDBRow).build());
        }
        return myRichObjects;
    }
}

关于android - 如何在后台线程上执行 LiveData 转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47374580/

相关文章:

java - Gradle 找不到 JAVA_HOME @Linux Mint

Android Room 递归关系

java - MVVM + 数据绑定(bind) + View 模型不更新 View

android - Room 和 rxjava 数据库不工作?

android - 创建我们自己的应用程序的快捷方式

android - 接口(interface)回调上的 fragment 空指针异常

android - 使用 Room Persistence Storage 在 Sqlite 中更改列的数据类型

android - Repository 方法在 Asynchronous Retrofit 调用中设置 LiveData 值

java - 如何在 LinearLayout 中添加 MapView 和其他组件?

Android - 用于处理 IllegalStateException : Cannot access database on the main thread 的 Kotlin 协程