如何在后台线程上执行LiveData转换? [英] How can I perform LiveData transformations on a background thread?
问题描述
我需要将 LiveData
对象返回的一种类型的数据转换为在后台线程上的另一种形式,以防止UI滞后.
I have a need to transform one type of data, returned by a LiveData
object, into another form on a background thread to prevent UI lag.
在我的特定情况下,我有:
In my specific case, I have:
-
MyDBRow
对象(由原始long
s和String
s组成的POJO); - a 房间
MyDBRow
objects (POJOs consisting of primitivelong
s andString
s);- a Room DAO instance emitting these via a
LiveData<List<MyDBRow>>
; and - a UI expecting richer
MyRichObject
objects (POJOs with the primitives inflated into e.g. date/time objects)
所以我需要将我的 LiveData< List< MyDBRow>
转换为 LiveData< List< MyRichObject>>
,但是不在UI上线程.
so I need to transform my LiveData<List<MyDBRow>>
into a LiveData<List<MyRichObject>>
, but not on the UI thread.
- The original, "source"
LiveData
can be monitored by a newObserver
instance. - This
Observer
instance, when sourceLiveData
is emitted, can prepare a background thread to perform the needed transformation and then emit it via a new, "transformed"LiveData
. - The transformed
LiveData
can attach the aforementionedObserver
to the sourceLiveData
when it has activeObserver
s, and detach them when it doesn't, ensuring that the sourceLiveData
is only being observed when necessary.
该问题给出了示例源 LiveData< List< MyDBRow>>
,并且需要转换后的 LiveData< List< MyRichObject>>
.组合后的转换后的 LiveData
和 Observer
可能看起来像这样:
The question gives an example source LiveData<List<MyDBRow>>
and needs a transformed LiveData<List<MyRichObject>>
. A combined transformed LiveData
and Observer
could look something like this:
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);
}
});
}
}
如果需要多次这样的转换,可以使上述逻辑通用,如下所示:
If multiple such transformations are needed, the above logic could be made generic like this:
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);
}
以及该问题给出的示例的子类可能看起来像这样:
and the subclass for the example given by the question could look something like this:
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;
}
}
这篇关于如何在后台线程上执行LiveData转换?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!