LiveData类的这两个方法之间有什么区别?官方的文档和教程对此相当模糊。在map()方法中,第一个参数称为源,但在switchMap()中,称为触发器。这背后的理由是什么?
发布于 2017-12-07 08:05:12
根据文件
对存储在LiveData对象中的值应用一个函数,并将结果传播到下游。
类似于map,向存储在LiveData对象中的值应用一个函数,并向下游展开和分发结果。传递给switchMap()的函数必须返回LiveData对象。
换句话说,我可能不是100%正确,但如果您熟悉RxJava;Transformations#map
有点类似于Observable#map
& Transformations#switchMap
类似于Observable#switchMap
。
让我们举个例子,有一个LiveData,它发出一个字符串,我们希望用大写字母显示这个字符串。
一种方法如下:在一个活动或片段中
Transformations.map(stringsLiveData, String::toUpperCase)
.observe(this, textView::setText);
传递给map
的函数只返回一个字符串,但最终返回一个LiveData
的是Transformation#map
。
第二种方法;在一种活动或片段中
Transformations.switchMap(stringsLiveData, this::getUpperCaseStringLiveData)
.observe(this, textView::setText);
private LiveData<String> getUpperCaseStringLiveData(String str) {
MutableLiveData<String> liveData = new MutableLiveData<>();
liveData.setValue(str.toUpperCase());
return liveData;
}
如果您看到,Transformations#switchMap
实际上已经切换了LiveData
。因此,与文档一样,传递给switchMap()的函数必须返回LiveData对象。
因此,在map
的情况下,您正在转换的是源 LiveData
,如果是switchMap
,则传递的LiveData
将充当触发器,在展开和向下游发送结果之后,它将切换到另一个LiveData
。
发布于 2018-03-28 17:57:16
我的观察是,如果您的转换过程很快(不涉及数据库操作或网络活动),那么您可以选择使用map
。
但是,如果转换过程缓慢(涉及数据库操作或网络活动),则需要使用switchMap
。
在执行耗时的操作时使用switchMap
。
class MyViewModel extends ViewModel {
final MutableLiveData<String> mString = new MutableLiveData<>();
final LiveData<Integer> mCode;
public MyViewModel(String string) {
mCode = Transformations.switchMap(mString, input -> {
final MutableLiveData<Integer> result = new MutableLiveData<>();
new Thread(new Runnable() {
@Override
public void run() {
// Pretend we are busy
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int code = 0;
for (int i=0; i<input.length(); i++) {
code = code + (int)input.charAt(i);
}
result.postValue(code);
}
}).start();
return result;
});
if (string != null) {
mString.setValue(string);
}
}
public LiveData<Integer> getCode() {
return mCode;
}
public void search(String string) {
mString.setValue(string);
}
}
map
不适用于耗时的操作。
class MyViewModel extends ViewModel {
final MutableLiveData<String> mString = new MutableLiveData<>();
final LiveData<Integer> mCode;
public MyViewModel(String string) {
mCode = Transformations.map(mString, input -> {
/*
Note: You can't launch a Thread, or sleep right here.
If you do so, the APP will crash with ANR.
*/
/*
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
*/
int code = 0;
for (int i=0; i<input.length(); i++) {
code = code + (int)input.charAt(i);
}
return code;
});
if (string != null) {
mString.setValue(string);
}
}
public LiveData<Integer> getCode() {
return mCode;
}
public void search(String string) {
mString.setValue(string);
}
}
发布于 2019-02-03 11:05:22
首先,map()
和switchMap()
方法都是在主线程上调用的。它们与被用于快速或缓慢任务无关。但是,如果在这些方法中执行复杂的计算任务或耗时任务,而不是工作线程,解析或转换长和/或复杂的json响应(例如,因为它们是在UI线程上执行),则可能会导致UI滞后。
map()方法的代码是
@MainThread
public static <X, Y> LiveData<Y> map(@NonNull LiveData<X> source,
@NonNull final Function<X, Y> func) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
result.addSource(source, new Observer<X>() {
@Override
public void onChanged(@Nullable X x) {
result.setValue(func.apply(x));
}
});
return result;
}
它所做的是使用源LiveData,I是输入类型,并在LiveData上调用setValue(O),其中O是输出类型。
为了清楚起见,让我举一个例子。当用户更改时,您希望将用户名和姓氏写入textView。
/**
* Changes on this user LiveData triggers function that sets mUserNameLiveData String value
*/
private MutableLiveData<User> mUserLiveData = new MutableLiveData<>();
/**
* This LiveData contains the data(String for this example) to be observed.
*/
public final LiveData<String> mUserNameLiveData;
现在,让我们在mUserLiveData更改时触发对mUserNameLiveData的字符串的更改。
/*
* map() method emits a value in type of destination data(String in this example) when the source LiveData is changed. In this example
* when a new User value is set to LiveData it trigger this function that returns a String type
*
* Input, Output
* new Function<User, String>
*
* public String apply(User input) { return output;}
*/
// Result<Output> Source<Input> Input, Output
mUserNameLiveData = Transformations.map(mUserLiveData, new Function<User, String>() {
@Override
public String apply(User input) {
// Output
return input.getFirstName() + ", " + input.getLastName();
}
});
让我们用MediatorLiveData
做同样的事情
/**
* MediatorLiveData is what {@link Transformations#map(LiveData, Function)} does behind the scenes
*/
public MediatorLiveData<String> mediatorLiveData = new MediatorLiveData<>();
/*
* map() function is actually does this
*/
mediatorLiveData.addSource(mUserLiveData, new Observer<User>() {
@Override
public void onChanged(@Nullable User user) {
mediatorLiveData.setValue(user.getFirstName() + ", " + user.getLastName());
}
});
如果在活动或片段上观察到MediatorLiveData,就会得到与观察LiveData<String> mUserNameLiveData
相同的结果。
userViewModel.mediatorLiveData.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
TextView textView = findViewById(R.id.textView2);
textView.setText("User: " + s);
Toast.makeText(MainActivity.this, "User: " + s, Toast.LENGTH_SHORT).show();
}
});
每次更改switchMap()时,都会返回相同的MediatorLiveData,而不是新的 LiveData。
它的源代码是
@MainThread
public static <X, Y> LiveData<Y> switchMap(@NonNull LiveData<X> trigger,
@NonNull final Function<X, LiveData<Y>> func) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
result.addSource(trigger, new Observer<X>() {
LiveData<Y> mSource;
@Override
public void onChanged(@Nullable X x) {
LiveData<Y> newLiveData = func.apply(x);
if (mSource == newLiveData) {
return;
}
if (mSource != null) {
result.removeSource(mSource);
}
mSource = newLiveData;
if (mSource != null) {
result.addSource(mSource, new Observer<Y>() {
@Override
public void onChanged(@Nullable Y y) {
result.setValue(y);
}
});
}
}
});
return result;
}
基本上,它所做的是创建一个最终的MediatorLiveData,并像map to ()一样设置结果,但是这次函数返回LiveData
public static <X, Y> LiveData<Y> map(@NonNull LiveData<X> source,
@NonNull final Function<X, **Y**> func) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
result.addSource(source, new Observer<X>() {
@Override
public void onChanged(@Nullable X x) {
result.setValue(func.apply(x));
}
});
return result;
}
@MainThread
public static <X, Y> LiveData<Y> switchMap(@NonNull LiveData<X> trigger,
@NonNull final Function<X, **LiveData<Y>**> func) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
result.addSource(trigger, new Observer<X>() {
LiveData<Y> mSource;
@Override
public void onChanged(@Nullable X x) {
LiveData<Y> newLiveData = func.apply(x);
if (mSource == newLiveData) {
return;
}
if (mSource != null) {
result.removeSource(mSource);
}
mSource = newLiveData;
if (mSource != null) {
result.addSource(mSource, new Observer<Y>() {
@Override
public void onChanged(@Nullable Y y) {
result.setValue(y);
}
});
}
}
});
return result;
}
因此,map()
接受LiveData<User>
并将其转换为String
,例如,如果User
对象更改了名称字段。
switchMap()
接受一个字符串并使用它获取LiveData<User>
。使用字符串从web或db查询用户,结果得到一个LiveData<User>
。
https://stackoverflow.com/questions/47575961
复制相似问题