LiveData是可观察的数据持有者类。与常规的可观察对象不同,LiveData具有生命周期感知功能,这意味着它尊重其他应用程序组件(例如活动,片段或服务)的生命周期。这种意识确保LiveData仅更新处于活动生命周期状态的应用程序组件观察者。
1、确保用户界面与数据状态匹配
LiveData遵循观察者模式。Lifecycle对象生命周期状态更改时,LiveData会通知对象。这样不用单独处理数据比ui早的问题。
2、没有内存泄漏
观察者绑定到 Lifecycle对象,并在其相关的生命周期被破坏时自行清理。
3、活动停止不会导致崩溃
如果观察者的生命周期处于非活动状态(例如Activity处于非活动状态),则观察者不会收到任何LiveData事件。
4、不再需要人工生命周期处理
UI组件仅观察相关数据,而不会停止或继续观察。LiveData自动管理所有这些,因为它在观察的同时知道相关生命周期状态的变化。
5、始终最新的数据
如果生命周期变为非活动状态,则在再次处于活动状态时它将接收最新数据。例如,在后台的Activity返回到前台后会立即接收最新数据。
6、正确的配置更改
如果由于配置更改(例如设备旋转)而重新创建Activity或Fragment,则该Activity或者Fragment将立即接收最新的可用数据。
7、共享资源
LiveData 使用单例模式扩展对象以包装系统服务,以便可以在您的应用程序中共享它们。该LiveData对象一次连接到系统服务,然后任何需要资源的观察者都可以监视该LiveData 对象。
1、创建LiveData对象
public class NameViewModel {
// Create a LiveData with a String
private MutableLiveData<String> currentName;
public MutableLiveData<String> getCurrentName() {
if (currentName == null) {
currentName = new MutableLiveData<String>();
}
return currentName;
}
}
2、观察LivewData对象
public class NameActivity extends AppCompatActivity {
private NameViewModel model;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
......
model = new NameViewModel();
// Create the observer which updates the UI.
final Observer<String> nameObserver = new Observer<String>() {
@Override
public void onChanged(@Nullable final String newName) {
// Update the UI, in this case, a TextView.
nameTextView.setText(newName);
}
};
//观察LiveData,并以LifecycleOwner和观察者的身份传入此活动。
model.getCurrentName().observe(this,nameObserver);
}
}
Observer在收到LiveData状态变更回调onChanged()方法。有些时候可能项目中并没有实现Lifecycle并且着急使用LiveData,可以使用observeForever()方法,但是在Activity或者Fragment销毁时记得removeObserver。
3、更新LiveData数据
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String anotherName = "John Doe";
model.getCurrentName().setValue(anotherName);
}
});
如果主线程调用setValue(),子线程调用postValue()
一般我们在项目中会使用RxJava等请求耗时任务,会在Activity.onCreate中启动任务,onDestroy销毁任务,同时还得处理回调。这些扩展LiveData就可以做到!!
public class GetNameLiveData extends LiveData<String> {
private NetworkRequestManager manager;
// listener用于监听网络数据,监听到后setValue通知所有观察者
private NetworkDataCallBack listener = new NetworkDataCallBack() {
@Override
public void onNameUpload(String name) {
if (isMainThread) {
setValue(name);
} else {
postValue(name);
}
}
};
public GetNameLiveData() {
manager = new NetworkRequestManager();
}
// onActive会在有Observe添加的时候调用
@Override
protected void onActive() {
// 这里请求网络,获取name,注意这个回调是主线程回调
new Thread(new Runnable() {
@Override
public void run() {
manager.requestName(listener);
}
}).start();
}
// onInactive会在没有任何Observe的时候调用
@Override
protected void onInactive() {
// 这里取消网络请求
manager.cacelRequest();
}
private boolean isMainThread() {
return Looper.myLooper() == Looper.getMainLooper();
}
}
// 定义网络请求的接口回调
private interface NetworkDataCallBack {
void onNameUpload(String name);
}
这样处理就不用切换线程、不用分发数据,不用随着Activity生命周期启动和取消任务。
需求场景:例如,从网络获取到商品信息是一个json的String,既有android数据库监听存储这个json,又有UI获取到数据做展示。你可以通过此方法转换。
MutableLiveData<String> liveData = new MutableLiveData<>();
liveData.observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
// 存储到数据库
}
});
LiveData<ProductInfo> productInfoLiveData = Transformations.map(liveData, new Function<String, ProductInfo>() {
@Override
public ProductInfo apply(String json) {
return new ProductInfo(json);
}
});
// 这么做就不用每个地方处理ProductInfo转换了
productInfoLiveData.observe(this, new Observer<ProductInfo>() {
@Override
public void onChanged(ProductInfo productInfo) {
// UI 展示
}
});
需求:例如,你需要通过一个name参数获取一个LiveData对象,然后添加Observe监听这个LiveData对象。
一般做法:
class MyViewModel {
private final HashMap<String, LiveData<String>> mLiveDataMap;
public MyViewModel(HashMap<String, LiveData<String>> liveDataMap) {
mLiveDataMap = liveDataMap;
}
public LiveData<String> getNameMapLiveData(String name) {
return mLiveDataMap.get(name);
}
}
分析下这个做法的弊端:
很明显,因为getNameMapLiveData获取到的是不同的LiveData对象,所以监听这个LiveData的Observer对象,需要每次getNameMapLiveData获取到新的LiveData对象后再做一次addObserve()操作,同时还需要解除之前观察的LiveData对象。
谷歌提供的神奇的办法:
class MyViewModel {
private final HashMap<String, LiveData<String>> mLiveDataMap;
private final MutableLiveData<String> nameLiveData = new MutableLiveData();
public final LiveData<String> mNameMapLiveData;
public MyViewModel(HashMap<String, LiveData<String>> liveDataMap) {
mLiveDataMap = liveDataMap;
mNameMapLiveData = Transformations.switchMap(nameLiveData, new Function<String, LiveData<String>>() {
@Override
public LiveData<String> apply(String name) {
return mLiveDataMap.get(name);
}
});
}
private void setName(String address) {
nameLiveData.setValue(address);
}
}
Transformations.switchMap自动帮你把Observe做了转换,你不再需要自己处理LiveData对象替换导致的观察者变动。
MediatorLiveData允许您合并多个LiveData。只要MediatorLiveData对象发生更改,就会触发它的LiveData集合。
例如,如果LiveData在UI中有一个可以从本地数据库或网络更新的对象,则可以将以下源添加到该 MediatorLiveData对象:
LiveData与存储在数据库中的数据关联的对象。
LiveData与从网络访问的数据关联的对象
一、LiveData如何分发Observe的
1、先看下LiveData的observe()方法
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
new SafeIterableMap<>();
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
......
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
......
}
很明显新增的观察者放到了mObservers集合
2、setValue是如何分发的
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
void dispatchingValue(@Nullable ObserverWrapper initiator) {
......
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
......
}
这里看到对mObservers集合做了遍历,最终到了considerNotify()
private void considerNotify(ObserverWrapper observer) {
......
observer.mLastVersion = mVersion;
//noinspection unchecked
observer.mObserver.onChanged((T) mData);
}
很简单就是一个集合的遍历,啥也没有。回调observer.onChanged方法。
3、看下子线程的postValue()
protected void postValue(T value) {
......
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
//noinspection unchecked
setValue((T) newValue);
}
};
也很简单,利用ArchTaskExecutor回调到了主线程,主线程setValue()分发。
二、LiveData关联Lifecycle,避免内存泄露
对Lifecycle使用不理解的,可以先看下这篇文章lifecycle原理分析
1、还是先看下Observe()方法
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
......
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
......
owner.getLifecycle().addObserver(wrapper);
}
owner.getLifecycle().addObserver()很明显给包装的LifecycleBoundObserver添加了生命周期关联
2、看一下LifecycleBoundObserver
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
......
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
......
}
Lifecycle在状态为DESTROYED时把Observer全部移除了,所以关联了lifecycle的LiveData不会发生内存泄露问题。
三、Transformations.map原理
1、看下MediatorLiveData包装类
public class MediatorLiveData<T> extends MutableLiveData<T> {
private SafeIterableMap<LiveData<?>, Source<?>> mSources = new SafeIterableMap<>();
public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
Source<S> e = new Source<>(source, onChanged);
Source<?> existing = mSources.putIfAbsent(source, e);
if (existing != null && existing.mObserver != onChanged) {
throw new IllegalArgumentException(
"This source was already added with the different observer");
}
if (existing != null) {
return;
}
if (hasActiveObservers()) {
e.plug();
}
}
private static class Source<V> implements Observer<V> {
final LiveData<V> mLiveData;
final Observer<? super V> mObserver;
int mVersion = START_VERSION;
Source(LiveData<V> liveData, final Observer<? super V> observer) {
mLiveData = liveData;
mObserver = observer;
}
void plug() {
mLiveData.observeForever(this);
}
void unplug() {
mLiveData.removeObserver(this);
}
@Override
public void onChanged(@Nullable V v) {
if (mVersion != mLiveData.getVersion()) {
mVersion = mLiveData.getVersion();
mObserver.onChanged(v);
}
}
}
}
MediatorLiveData很明显做了一个LiveData的包装集合。addSource()对传入的LiveData对象增加了一个新的Observe观察者,这个新增的观察者又桥接到了addSource()传入的Observer。
2、看下Transformations.map()方法
public static <X, Y> LiveData<Y> map(
@NonNull LiveData<X> source,
@NonNull final Function<X, Y> mapFunction) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
result.addSource(source, new Observer<X>() {
@Override
public void onChanged(@Nullable X x) {
result.setValue(mapFunction.apply(x));
}
});
return result;
}
这里会有点绕。map()方法最终的结果就是当source这个LiveData对象发生变更时,会分发到addSource()的第二个参数的onChanged()方法。因为result本身就是一个LiveData,所以调用result.setValue()就成功的链式分发到了map返回的LiveData对象。而mapFunction.apply(x)就是做了下数据处理。
四、Transformations.switchMap原理
搞懂了Map方法,switchMap就好理解一些了。
直接看switchMap代码:
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);
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方法的不同是这里的onChange做了两次Observe观察者传递,当switchMapFunction.apply(x)返回新的LiveData对象后,会重新为这个对象添加一个Obsever,然后当新的LiveData对象状态变更时会通过这个Observe通知result。
这里根据代码解析switchMap的优点
(1)上边讲了switchMap会动态的变更LiveData对象,那么如何保证变更LiveData对象后,Observe集合没有变动呢?
final MediatorLiveData result = new MediatorLiveData<>();很明显,switchMap返回的result是一个new LiveData,并不是LiveData newLiveData = switchMapFunction.apply(x)返回的LiveData,所以虽然我们在apply变动了LiveData,但是switchMap返回的LiveData对象从来没有变过。
(2)switchMap会变更LiveData,如何保证已经废弃的LiveData不会再触发Observe观察者?
if (mSource != null) {
result.removeSource(mSource);
}
因为MediatorLiveData对象内部有一个LiveData集合,所以remove掉后,集合遍历就找不到这个失效的LiveData对象了,也就不会触发Observe。