赞
踩
Transformations 类是 LiveData 的一个功能扩展类,其是一个私有化构造方法的工具类,且只提供 3 个方法使用,虽然数量不多,但胜在实用,这三个方法分别是:
那么接下来我们就一一分析每个方法及其源码实现过程,如果想要更清楚的了解源码建议先了解 这篇文章。
其实看名字我们就能大概知道这个方法是个什么样的存在……
类似于 RxJava 的 map 操作符、Kotlin 中数组的扩展函数 map,其实 Transformations 的 map 方法也是一个转化的功能。
先看看效果:
private val originData = MutableLiveData<String>()
// 通过 Transformations.map 返回一个 LiveData
val mapData = Transformations.map(originData, Function<String,String> {
it.plus(" World")
})
mapData.observe(this, Observer {
Log.e("mapData",it)
})
// 点击按钮给 originData 赋值
btn.setOnClickListener {
originData.value = "Hello"
}
控制台输出:
mapData: Hello World
相信大家也看到了,map()
方法的第二个参数的类型有两个泛型,事实上第一个个泛型的类型是确定的,那就是对应 map()
方法第一个参数 LiveData 的泛型,那么第二个泛型就是控制返回的 LiveData 的类型。改造上面的例子:
... ...
val mapData = Transformations.map(originData, Function<String,Int> {
it.length
})
mapData.observe(this, Observer {
Log.e("mapData",it.toString())
})
... ...
控制台输出:
mapData: 5
... ...
val mapData = originData.map {it.plus("world")}
... ...
如果遇到报错:Cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1,那就在模块的 gradle 中添加:
android{
... ...
kotlinOptions{
jvmTarget = 1.8
}
}
源码还是非常简单的:
@MainThread @NonNull public static <X, Y> LiveData<Y> map( @NonNull LiveData<X> source, @NonNull final Function<X, Y> mapFunction) { final MediatorLiveData<Y> result = new MediatorLiveData<>(); //1 result.addSource(source, new Observer<X>() { //2 @Override public void onChanged(@Nullable X x) { result.setValue(mapFunction.apply(x)); //3 } }); return result; //4 } public interface Function<I, O> { O apply(I input); }
result
添加监听,使得原 source
发生变化的时候会发生回调,执行 onChanged()
方法。mapFunction.apply(x)
类似于 Kotlin 的高阶函数,将源值暴露出去,让我们去直接接触这个值,并且对其操作转换。看名字,是不是又联想到了 RxJava 的 switchMap 操作符?
实际上 Transformations 的 switchMap 也是一样的功能:舍弃原来的 LiveData,创建一个新的 LiveData 来接管它的变化。
private val originData = MutableLiveData<String>()
// 通过 Transformations.switchMap返回一个 LiveData
val switchMapData = Transformations.switchMap(originData, Function {
return@Function MutableLiveData<String>().apply {
this.value = it.plus("world")
}
})
switchMapData.observe(this, Observer {
Log.e("switchMapData",it)
})
// 点击按钮给 originData 赋值
btn.setOnClickListener {
originData.value = "Hello"
}
控制台输出:
switchMapData: Hello world
对比一下 map()
方法,switchMap()
显得如此的不堪……但存在即合理,它的也有它的使用场景。
我们先对比一下 switchMap()
和 map()
的使用过程:map()
的操作已经是在消费上层 LiveData 的值,而 switchMap()
同样使消费了上层 LiveData 的值,但是它又创建了新的生产者,所以其真实的消费并不是由 switchMap()
来执行的。
知道了这点后,我们就可以比较清晰的了解 switchMap()
的使用场景了:那就是通过其创建一个新的 LiveData,并且我们可以在其间做一些操作,无论是单纯的转变类型,或是时间上的耗时操作……
... ...
val switchMapData = originData.switchMap {
return@switchMap MutableLiveData<String>().apply {
this.value = it.plus("world")
}
}
... ...
@MainThread @NonNull public static <X, Y> LiveData<Y> switchMap( @NonNull LiveData<X> source, @NonNull final Function<X, LiveData<Y>> switchMapFunction) { final MediatorLiveData<Y> result = new MediatorLiveData<>(); result.addSource(source, new Observer<X>() { LiveData<Y> mSource; @Override public void onChanged(@Nullable X x) { LiveData<Y> newLiveData = switchMapFunction.apply(x); //1 if (mSource == newLiveData) { //2 return; } if (mSource != null) { result.removeSource(mSource); //3 } mSource = newLiveData; if (mSource != null) { result.addSource(mSource, new Observer<Y>() { //4 @Override public void onChanged(@Nullable Y y) { result.setValue(y); } }); } } }); return result; }
前面还是同样的操作,创建一个 MediatorLiveData 来接管源 source
的变化。
newLiveData
就是我们在外面自己创建的。switchMap()
中返回相同的 LiveData 其实是不起作用的。mSource
存在值,对应的就是之前 switchMap()
中返回的 LiveData ,这时候就会进行一个 removeSource()
的操作,从这里我们也恶意得到一个很有用的信息:如果我们在 switchMap()
中返回不同的 LiveData ,那么之前的 LiveData 就会失效。这个方法的作用就没有 RxJava 作为参考了……
所以就直接说这个方法的作用是怎样的吧:这个方法也能够返回一个监听 source
的 LiveData,当源 LiveData 发生变化 ,其返回的 LiveData 也能够发生变化……(这可不就是map()
吗?( ఠൠఠ )ノ) ,但不同的是,如果源 LiveData 一直进行 setValue()/postValue()
同一个值,那么返回的 LiveData 只接收第一次返回的值,除非源 LiveData 设置新的值。
private val originData = MutableLiveData<String>()
// 通过 Transformations.distinctUntilChanged 返回一个 LiveData
val newData = Transformations.distinctUntilChanged(originData)
newData.observe(this, Observer {
Log.e("newData",it)
})
// 点击按钮给 originData 赋值
btn.setOnClickListener {
originData.value = "Hello"
}
然后疯狂的点击按钮,而控制台只有一行输出,并且通过源码我们也能够发现它没有转换类型的功能,source
的类型是怎样的,那么返回的 LiveData 的类型就是怎样的。
val newData = originData.distinctUntilChanged()
@MainThread @NonNull public static <X> LiveData<X> distinctUntilChanged(@NonNull LiveData<X> source) { final MediatorLiveData<X> outputLiveData = new MediatorLiveData<>(); outputLiveData.addSource(source, new Observer<X>() { boolean mFirstTime = true; //1 @Override public void onChanged(X currentValue) { final X previousValue = outputLiveData.getValue(); //2 if (mFirstTime || (previousValue == null && currentValue != null) || (previousValue != null && !previousValue.equals(currentValue))) { //3 mFirstTime = false; //4 outputLiveData.setValue(currentValue); //4 } } }); return outputLiveData; }
前面仍然是索然无味的 MediatorLiveData 来接管上层的 LiveData 的变化。
mFirstTime
一定为 false,先执行 (previousValue == null && currentValue != null)
来进行判空的操作,这里 previousValue
一定是不为空的,所以整个句式返回的也是 false,那么接下来就是值的对比,对比现在的值和新的值是否相等,如果相等的话也会返回 false ,所以一系列的分析下来,我们就可以得出上面刚开始的结论。Transformations 的 3 个函数都十分的具有实用性,在具体的开发过程中,我们在业务层完全就可以依赖 LiveData 去实现值的传递的过程,甚至是变换的过程。使用起来也具有较强的灵活性、技巧性,实乃居家必备之良药。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。