一、介绍
1、LiveData
LiveData是一种可观察的数据存储器类。与常规的可观察类不同,LiveData具有生命周期感知能力,意指它遵循其他应用组件(如Activity
、Fragment
或Service
的生命周期。这种感知能力可确保LiveData仅更新处于活跃生命周期状态的应用组件观察者。 如果观察者(由Observer
类表示)的生命周期处于STARTED
或RESUMED
状态,则LiveData会认为该观察者处于活跃状态。LiveData只会将更新通知给活跃的观察者。为观察LiveData对象而注册的非活跃观察者不会收到更改通知。
2、ViewModel
ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据。主要作用是对数据状态的持有和维护。可以用来解决以下两个问题:
-
Activity配置更改重建时(比如屏幕旋转)保留数据
-
UI组件(Activity与Fragment、Fragment与Fragment)间实现数据共享
ViewModel通常与LiveData这个数据驱动器结合在一起使用。将用于更新界面的 LiveData
对象存储在 ViewModel
对象中,而不是将其存储在 Activity 或 Fragment 中,原因如下:
-
避免 Activity 和 Fragment 过于庞大。界面控制器只负责显示数据,不负责存储数据状态。
-
将
LiveData
实例与特定的 Activity 或 Fragment 实例分离开。这样LiveData
对象在配置更改后可以继续存在。
LiveData提供感知lifecycle生命周期的数据通知能力,viewModel作为存储LiveData避免被宿主销毁的容器。
二、基本使用
1、LiveData使用
1)创建LiveData对象
MutableLiveData<String> liveData = new MutableLiveData<>();
2)观察LiveData对象
通过observe
方法来监听LiveData
的数据变化,每当LiveData
发生变化时,都会回调onChanged
方法,并返回值的内容
liveData.observe(this, new Observer<String>() { @Override public void onChanged(String s) { //更新UI }});
3)更新LiveData对象
通过LiveData
的setValue
方法,给LiveData
赋值,每次赋完值后,都会回调onChanged
方法。如果是在异步子线程中更新数据,在主线程更新监听,则需要调用postValue方法。
liveData.postValue("a");liveData.setValue("b");
2、结合ViewModel使用
1)在ViewModel中存储LiveData对象
public class PtListViewModel extends ViewModel {private final MutableLiveData<List<SupposeItem>> supposeListLiveData = new MutableLiveData<>(); public MutableLiveData<List<SupposeItem>> getSupposeListLiveData() { return supposeListLiveData; } public void setSupposeList(List<SupposeItem> list){ supposeListLiveData.setValue(list); }}
2)在Activity的onCrete阶段观察LiveData
final PtListViewModel mViewModel = new ViewModelProvider(mContext).get(PtListViewModel.class); mViewModel.getSupposeListLiveData().observe(mContext, supposeItems -> ());
每当有值发生变化时,就会收到最新值的通知。一旦应用组件处于 STARTED
状态,就会从它正在观察的 LiveData
对象接收最新值
3)更新LiveData值
可以结合网络请求或者需要在不同Fragment之间传递某些状态/筛选值时,通过setValue或postValue传值
new ViewModelProvider(JobInfoListFragmentActivity.this).get(PtListViewModel.class).setSupposeList(bean.data);
三、原理解析
1、注册监听observer()
@MainThread public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { assertMainThread("observe"); if (owner.getLifecycle().getCurrentState() == DESTROYED) { // ignore return; } LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer); ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); if (existing != null && !existing.isAttachedTo(owner)) { throw new IllegalArgumentException("Cannot add the same observer" + " with different lifecycles"); } if (existing != null) { return; } owner.getLifecycle().addObserver(wrapper); }
调用observer()
时,传递了两个参数,第一个是LifecycleOwner
接口实例,第二个参数Observer
就是我们观察的回调。接下来将这两个参数传递new出了一个新的对象:LifecycleBoundObserver
,最后将LifecycleBoundObserver
和LifecycleOwner
进行了绑定。
2、LifecycleBoundObserver
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver { @NonNull final LifecycleOwner mOwner; LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) { super(observer); mOwner = owner; } @Override boolean shouldBeActive() { return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED); } //Activity生命周期变化时,回调方法 @Override public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
//destroy状态解绑,可以避免内存泄漏
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) { removeObserver(mObserver); return; } //只有是Active状态才会去更新livedata activeStateChanged(shouldBeActive()); } @Override boolean isAttachedTo(LifecycleOwner owner) { return mOwner == owner; } //解除监听 @Override void detachObserver() { mOwner.getLifecycle().removeObserver(this); } }
可以看到这里面与LifecycleOwner
进行了绑定,并且实现了onStateChanged
方法,当生命周期发生变化时执行activeStateChanged(shouldBeActive());
方法;shouldBeActive()
返回了 要求生命周期至少是STARTED状态才被认为是activie状态;如果state是DESTROYED
状态时,则移除观察者,在 Activity、Fragment的生命周期走到 onDestroy 的时候,就会取消订阅,避免内存泄漏。
3、dispatchingValue()
继续追踪activeStateChanged
方法发现,在里面做了一些活跃状态值的操作,并且当状态活跃时,更新数据值。
void activeStateChanged(boolean newActive) { if (newActive == mActive) { return; } // immediately set active state, so we\'d never dispatch anything to inactive // owner mActive = newActive;.... if (mActive) { dispatchingValue(this); } }
void dispatchingValue(@Nullable ObserverWrapper initiator) { ... //遍历LiveData的所有观察者执行下面代码 for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator = mObservers.iteratorWithAdditions(); iterator.hasNext(); ) { considerNotify(iterator.next().getValue()); if (mDispatchInvalidated) { break; } } ...}//将数据值回调到livedata.observer()回去private void considerNotify(ObserverWrapper observer) { if (!observer.mActive) { return; } if (!observer.shouldBeActive()) { observer.activeStateChanged(false); return; } if (observer.mLastVersion >= mVersion) { return; } observer.mLastVersion = mVersion; observer.mObserver.onChanged((T) mData); }
可以看到当状态从不活跃到活跃状态,发生状态改变时。会遍历所有注册的观察者,判断数据version<=最新数据version(数据发生变化),就会调用观察者的onChanged来通知数据发生变化。
4、用户主动调用setValue()/postValue()
@MainThread protected void setValue(T value) { assertMainThread("setValue"); mVersion++; mData = value; dispatchingValue(null); }
private final Runnable mPostValueRunnable = new Runnable() { @SuppressWarnings("unchecked") @Override public void run() { Object newValue; synchronized (mDataLock) { newValue = mPendingData; mPendingData = NOT_SET; } setValue((T) newValue); } };
postValue()
在子线程更新数据,通过Hander做了线程切换,最终调用setValue方法。而setValue中就是调用了上面分析的 dispatchingValue通知观察者。
5、LiveData 的observeForever方法
这个方法比observe方法少一个LifecycleOwner参数,为啥呢?因为这个方法不需要感知生命周期,需要在setValue 值更新时立马收到回调。
6、LiveData的数据倒灌问题
倒灌现象:
先给LiveData设置了value,然后监听者才开始对LiveData进行监听,这时LiveData的value会立马回调给监听者
原因:
LiveData每次setValue或postValue时mVersion都会自增(见上文setValue源码),当调用LiveData进行observe时,最终会调到如下方法
private void considerNotify(ObserverWrapper observer) { ... if (observer.mLastVersion >= mVersion) { return; } observer.mLastVersion = mVersion; observer.mObserver.onChanged((T) mData); }
当observer的mLastVersion小于mVersion时就会把之前的数据回调给监听者,observer的mLastVersion的初始值为-1
static final int START_VERSION = -1;...int mLastVersion = START_VERSION;
当我们setValue时,mVersion会从-1开始自增,之后我们去observe时,由于observer的mLastVersion的初始值是-1,比mVersion=0小,所以调用observe时,会立马把旧的数据回调给观察者。
参考资料: