1.LifecycleOwner
Activityt等组件都是以LifecycleOwner的形式被LiveData感知的,LifecycleOwner只是一个简单的接口:
public interface LifecycleOwner {
Lifecycle getLifecycle();
}
但是普通的Activity和Fragment并没有实现这个接口,想要使用LiveData的特性需要使用:
import android.support.v7.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
...
}
import android.support.v4.app.Fragment;
public class MainFragment extends Fragment {
...
}
2.LiveData
LiveData是一个没有抽象方法的抽象类,它发射数据的方法的接口没有暴露给外部使用
public abstract class LiveData<T> {
protected void postValue(T value) {...}
@MainThread
protected void setValue(T value) {...}
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {...}
@MainThread
public void observeForever(@NonNull Observer<T> observer) {...}
}
MutableLiveData继承了LiveData,它只是暴露了发射数据的接口
public class MutableLiveData<T> extends LiveData<T> {
@Override
public void postValue(T value) {
super.postValue(value);
}
@Override
public void setValue(T value) {
super.setValue(value);
}
}
MediatorLiveData继承了MutableLiveData,它提供了addSource的接口
public class MediatorLiveData<T> extends MutableLiveData<T> {
private SafeIterableMap<LiveData<?>, Source<?>> mSources = new SafeIterableMap<>();
@MainThread
public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<S> onChanged){...}
@MainThread
public <S> void removeSource(@NonNull LiveData<S> toRemote)
private static class Source<V> implements Observer<V> {
final LiveData<V> mLiveData;
final Observer<V> mObserver;
}
}
MediatorLiveData的作用是,考虑到有些页面可能有非常多的LiveData,每个Livedata都要绑定到一个生命周期对象,这样就产生了大量的重复代码;
livedata1, livedata2..... livedata20;
livedata1.observe(owner, result->{})
livedata2.observe(owner, result->{})
...
livedata20.observe(owner, result->{})
MediatorLiveData类似于一个Map,它把liveData和它的观察者储存在这个Map中管理起来,MediatorLiveData自己去绑定并管理生命周期,这样就避免了每个LiveData都去绑定生命周期
mediatorLiveData.addSource(livedata1, observer1);
mediatorLiveData.addSource(livedata2, observer2);
...
mediatorLiveData.observe(lifecycleOwner, mediatOrbserver);
3.Transformations
Transformations提供了两个静态方法,它是用来对LiveData做变换的:
public class Transformations {
@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;
}
@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
map需要传入两个参数,一个是待变换的LiveData,另一个是变换函数,它可以理解为Rxjava中的map操作符
public interface Function<I, O> {
O apply(I input);
}
使用非常简单,例如:
MutableLiveData<String> originalLivedata = new MutableLiveData<>();
LiveData<String> transformedLiveData = Transformations.map(originalLivedata , s -> s + "?");
originalLivedata.observe(this,result -> { //Observer1
Log.d("originalLivedata", result);
});
TransformedLiveData.observe(this,result -> { //Observer2
Log.d("TransformedLiveData", result);
});
originalLivedata.setValue("Test");
在上面的测试中,两个Observer都会收到消息,分别打印了 Test 和 Test?
所以transformedLiveData
会监听originalLivedata
switchMap
switchMap传入的两个参数分别是一个LiveData和一个Function,这个Fuction把普通数据类型转化为LiveData数据类型
它和Rxjava中的flatMap操作符非常相似,是map的加强版:
MutableLiveData<String> originalLiveData = new MutableLiveData<>();
LiveData<String> transformedLiveData = Transformations.switchMap(originalLiveData, s -> {
MutableLiveData liveData = new MutableLiveData();
liveData.setValue(s + "?");
return liveData;
});
originalLiveData.observe(this, result -> {
Log.d("originalLivedata", result+"");
});
transformedLiveData.observe(this, result -> {
Log.d("transformedLiveData", result);
});
originalLiveData.setValue("Test");
效果和上面map是一样的
5.LiveData数据缓存:
Test:
public class MainViewModel {
public static MutableLiveData<String> liveData = new MutableLiveData<>();
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
...
//先让livedata发送一条消息
viewModel.liveData.postValue("Hello");
//在liveData发送消息一段时间后打开第二个TestActivity
Observable.timer(10, TimeUnit.SECONDS).subscribe(n-> startActivity(Intent(this, TestActivity.class))
);
}
}
public class TestActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
//打开TestActivity会收到livedata发送的最后一条消息,尽管发消息的时间是10s前
viewModel.liveData.observe(this, s -> Log.e("TestActivity ", s));
}
}
即一个生命周期对象监听一个Livedata的时候,会马上收到这个Livedata发送过的最后一条消息
Livedata的这种特性会导致这样一种情况:一个页面在退出前收到了一条来自某Livedata的消息M,当这个页面再次启动并重新订阅这个Livedata的时刻,会再次收到同一条
消息M
为了消除Livedata的这个特性,可以将发送的消息加一层封装,用来拦截掉已经处理过的消息:
public class Event<T> {
private T mContent;
private boolean hasBeenHandled = false;
public Event(T content) {
if (content == null) {
throw new IllegalArgumentException("null values in Event are not allowed.");
}
mContent = content;
}
public T getContentIfNotHandled() {
if (hasBeenHandled) {
return null;
} else {
hasBeenHandled = true;
return mContent;
}
}
public boolean hasBeenHandled() {
return hasBeenHandled;
}
public T peekContent() {
return mContent;
}
}
发送消息的时候把消息封在Event中:
livedata.postValue(new Event("Hello"));
livedata.observe(this, event -> {
String msg = event.getContentIfNotHandled();
Log.d("LivedataCacheTest", result);
});
这样就可以保证每条消息只会被处理一次