我需要转换一种类型的数据,由 LiveData
返回对象在后台线程中转化为另一种形式,以防止 UI 滞后。
在我的具体情况下,我有:
-
MyDBRow
对象(由原始long
和String
组成的 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
的干净方法是什么?发生转变:
- 在主线程之外的某个地方,以及
- 仅在需要时(即仅当某些东西正在观察预期的转换时)?
最佳答案
- 原文,“来源”
LiveData
可以通过新的Observer
进行监控实例。 - 这
Observer
实例,当来源LiveData
发出后,可以准备一个后台线程来执行所需的转换,然后通过一个新的、“转换后的”LiveData
发出它。 . - 转换后的
LiveData
可以附上前述的Observer
到源LiveData
当它有 Activity 时Observer
s,并在没有时分离它们,确保源LiveData
仅在必要时才被观察。
问题给出了例子来源LiveData<List<MyDBRow>>
并且需要一个转换后的 LiveData<List<MyRichObject>>
.组合转换 LiveData
和 Observer
可能看起来像这样:
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/