LiveData是一个数据持有者,其本身实现了观察者模式,支持数据监控(被观察),并且可以感知组件的生命周期。
观察者可以指定某一个LifeCycle(activity,fragment)。并对数据进行监听。
如果观察者指定LifeCycle处于Started或者RESUMED状态,LiveData会将观察者视为活动状态,并通知其数据的变化。
实战
先来看一下简单的使用,以下是一个Product列表。
我们首先来看一下数据的处理代码:
public class ProductListViewModel extends AndroidViewModel {
private final LiveData<List<ProductEntity>> mObservableProducts;
public ProductListViewModel(Application application) {
super(application);
final ProductDataRepository repository = new ProductDataRepository();
mObservableProducts = Transformations.switchMap(repository.isCreatedDatabase(), new Function<Boolean, LiveData<List<ProductEntity>>>() {
@Override
public LiveData<List<ProductEntity>> apply(Boolean input) {
if(!Boolean.TRUE.equals(input)){
return ABSENT;
}else{
return repository.getProducts();
}
}
});
}
public LiveData<List<ProductEntity>> getProducts() {
return mObservableProducts;
}
}
代码中将数据源定义成一个LiveData对象,LiveData中持有的是真正需要的数据List<ProductEntity>。
接下来看看UI层是如何使用的,请看下面代码:
public class ProductListFragment extends LifecycleFragment {
private ProductListAdapter adapter;
...
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
ProductListViewModel viewModel =
ViewModelProviders.of(this).get(ProductListViewModel.class);
subscribeUi(viewModel);
}
private void subscribeUi(ProductListViewModel viewModel){
viewModel.getProducts().observe(this, new Observer<List<ProductEntity>>() {
@Override
public void onChanged(@Nullable List<ProductEntity> productEntities) {
if(productEntities != null){
mBinding.setIsLoading(false);
adapter.setProducts(productEntities);
}else{
mBinding.setIsLoading(true);
}
}
});
}
}
可以看到viewModel.getProducts().observe(...)就是订阅数据。observe的第一个参数是LifeCycleOwner,即和生命周期绑定。
而ProductListFragment是继承自LifecycleFragment,LifecycleFragment就是一个LifecycleOwner,因此此处传入this。第二个参数是一个观察者,当数据发生变化是会通过该观察者来刷新。
下面通过分析Room对LiveData的支持来分析LiveData的工作原理
下面我们先看看从数据库中获取所有product的代码:
1、首先定义获取数据的dao接口,返回类型为LiveData
@Dao
public interface ProductDao {
@Query("select * from products")
LiveData<List<ProductEntity>> queryLiveProducts();
}
2、编译代码,会发现自动生成ProductDao的实现类ProductDao_Impl.java:
public class ProductDao_Impl implements ProductDao {
......//省略一大波代码
@Override
public LiveData<List<ProductEntity>> queryLiveProducts() {
final String _sql = "select * from products";
final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
return new ComputableLiveData<List<ProductEntity>>() {
private Observer _observer;
@Override
protected List<ProductEntity> compute() {
if (_observer == null) {
_observer = new Observer("products") {
@Override
public void onInvalidated() {
invalidate();
}
};
__db.getInvalidationTracker().addWeakObserver(_observer);
}
final Cursor _cursor = __db.query(_statement);
try {
final int _cursorIndexOfId = _cursor.getColumnIndexOrThrow("id");
final int _cursorIndexOfName = _cursor.getColumnIndexOrThrow("name");
final int _cursorIndexOfDescription = _cursor.getColumnIndexOrThrow("description");
final int _cursorIndexOfPrice = _cursor.getColumnIndexOrThrow("price");
final List<ProductEntity> _result = new ArrayList<ProductEntity>(_cursor.getCount());
while(_cursor.moveToNext()) {
final ProductEntity _item;
_item = new ProductEntity();
final Long _tmpId;
if (_cursor.isNull(_cursorIndexOfId)) {
_tmpId = null;
} else {
_tmpId = _cursor.getLong(_cursorIndexOfId);
}
_item.setId(_tmpId);
final String _tmpName;
_tmpName = _cursor.getString(_cursorIndexOfName);
_item.setName(_tmpName);
final String _tmpDescription;
_tmpDescription = _cursor.getString(_cursorIndexOfDescription);
_item.setDescription(_tmpDescription);
final double _tmpPrice;
_tmpPrice = _cursor.getDouble(_cursorIndexOfPrice);
_item.setPrice(_tmpPrice);
_result.add(_item);
}
return _result;
} finally {
_cursor.close();
}
}
@Override
protected void finalize() {
_statement.release();
}
}.getLiveData();
}
...... //省略一大波代码
}
这里我们只关心具体方法的实现,可以看到生成的代码中返回的是一个ComputableLiveData<List<ProductEntity>>对象,那么此对象是个啥玩意呢?让我们找到这个类看看:
public abstract class ComputableLiveData<T> {
private final LiveData<T> mLiveData;
......
/**
* Creates a computable live data which is computed when there are active observers.
* <p>
* It can also be invalidated via {@link #invalidate()} which will result in a call to
* {@link #compute()} if there are active observers (or when they start observing)
*/
@SuppressWarnings("WeakerAccess")
public ComputableLiveData() {
mLiveData = new LiveData<T>() {
@Override
protected void onActive() {
// TODO if we make this class public, we should accept an executor
AppToolkitTaskExecutor.getInstance().executeOnDiskIO(mRefreshRunnable);
}
};
}
/**
* Returns the LiveData managed by this class.
*
* @return A LiveData that is controlled by ComputableLiveData.
*/
@SuppressWarnings("WeakerAccess")
@NonNull
public LiveData<T> getLiveData() {
return mLiveData;
}
@VisibleForTesting
final Runnable mRefreshRunnable = new Runnable() {
@WorkerThread
@Override
public void run() {
boolean computed;
do {
computed = false;
// compute can happen only in 1 thread but no reason to lock others.
if (mComputing.compareAndSet(false, true)) {
// as long as it is invalid, keep computing.
try {
T value = null;
while (mInvalid.compareAndSet(true, false)) {
computed = true;
value = compute();
}
if (computed) {
mLiveData.postValue(value);
}
} finally {
// release compute lock
mComputing.set(false);
}
}
} while (computed && mInvalid.get());
}
};
// invalidation check always happens on the main thread
@VisibleForTesting
final Runnable mInvalidationRunnable = new Runnable() {
@MainThread
@Override
public void run() {
boolean isActive = mLiveData.hasActiveObservers();
if (mInvalid.compareAndSet(false, true)) {
if (isActive) {
// TODO if we make this class public, we should accept an executor.
AppToolkitTaskExecutor.getInstance().executeOnDiskIO(mRefreshRunnable);
}
}
}
};
/**
* Invalidates the LiveData.
* <p>
* When there are active observers, this will trigger a call to {@link #compute()}.
*/
public void invalidate() {
AppToolkitTaskExecutor.getInstance().executeOnMainThread(mInvalidationRunnable);
}
@SuppressWarnings("WeakerAccess")
@WorkerThread
protected abstract T compute();
}
可以看出这个类其实就是对Live的一层包装,并且处理了线程切换相关的东西。
首先在初始化类时会初始化LiveData
mLiveData = new LiveData<T>() {
@Override
protected void onActive() {
// TODO if we make this class public, we should accept an executor
AppToolkitTaskExecutor.getInstance().executeOnDiskIO(mRefreshRunnable);
}
};
并且如果当前组件处于active状态时会执行mRefreshRunnable。而这个runnable中的代码如下:
T value = null;
while (mInvalid.compareAndSet(true, false)) {
computed = true;
value = compute();
}
if (computed) {
mLiveData.postValue(value);
}
这段代码实现了两个功能。
1、获取需要的数据value = compute()
,
2、刷新数据mLiveData.postValue(value)
从上面代码中我们看到这个compute是个抽象方法,那么他是在哪里实现的呢?让我们回到Dao的实现类里看看,具体实现代码如下:
@Override
protected List<ProductEntity> compute() {
if (_observer == null) {
_observer = new Observer("products") {
@Override
public void onInvalidated() {
invalidate();
}
};
__db.getInvalidationTracker().addWeakObserver(_observer);
}
final Cursor _cursor = __db.query(_statement);
try {
final int _cursorIndexOfId = _cursor.getColumnIndexOrThrow("id");
final int _cursorIndexOfName = _cursor.getColumnIndexOrThrow("name");
final int _cursorIndexOfDescription = _cursor.getColumnIndexOrThrow("description");
final int _cursorIndexOfPrice = _cursor.getColumnIndexOrThrow("price");
final List<ProductEntity> _result = new ArrayList<ProductEntity>(_cursor.getCount());
while(_cursor.moveToNext()) {
final ProductEntity _item;
_item = new ProductEntity();
final Long _tmpId;
if (_cursor.isNull(_cursorIndexOfId)) {
_tmpId = null;
} else {
_tmpId = _cursor.getLong(_cursorIndexOfId);
}
_item.setId(_tmpId);
final String _tmpName;
_tmpName = _cursor.getString(_cursorIndexOfName);
_item.setName(_tmpName);
final String _tmpDescription;
_tmpDescription = _cursor.getString(_cursorIndexOfDescription);
_item.setDescription(_tmpDescription);
final double _tmpPrice;
_tmpPrice = _cursor.getDouble(_cursorIndexOfPrice);
_item.setPrice(_tmpPrice);
_result.add(_item);
}
return _result;
} finally {
_cursor.close();
}
}
可以看到这里是从数据库中查询数据并返回一个List对象。至此回去数据的流程大致走了一遍,接下来就是如何订阅的事情了。
订阅数据
这里采用了MVVM模式,ViewModel将数据发送到对应的UI界面来更新UI,这里抛开MVVM框架只看LiveData是如何更新UI的。
要想更新UI首先需要订阅对应的数据,也就是liveData。所以我们需要在Fragment/Activity中来订阅数据,代码如下:
viewModel.getProducts().observe(this, new Observer<List<ProductEntity>>() {
@Override
public void onChanged(@Nullable List<ProductEntity> productEntities) {
if(productEntities != null){
mBinding.setIsLoading(false);
adapter.setProducts(productEntities);
}else{
mBinding.setIsLoading(true);
}
}
});
这里getProducts()返回的是一个LiveData对象,通过调用observer方法将改Fragment的生命周期与LiveData绑定。下面我们看看Observer方法的代码:
public void observe(LifecycleOwner owner, Observer<T> observer) {
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
LifecycleBoundObserver existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && existing.owner != wrapper.owner) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper);
wrapper.activeStateChanged(isActiveState(owner.getLifecycle().getCurrentState()));
}
1、可以发现订阅是首先判断当前的状态,如果是destroyed时直接返回。
2、将传入的observer放到一个Map中。
3、将当前的页面加入生命周期的观察者map中,让其可被观察。
这样当页面的生命周期状态发生变化时会通知到LiveData,LiveData再去遍历所以的observer复合条件的发送数据更新。代码如下:
void activeStateChanged(boolean newActive) {
if (newActive == active) {
return;
}
active = newActive;
if (active) {
dispatchingValue(this);
}
}
private void dispatchingValue(@Nullable LifecycleBoundObserver initiator) {
......
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
for (Iterator<Map.Entry<Observer<T>, LifecycleBoundObserver>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
private void considerNotify(LifecycleBoundObserver observer) {
if (!observer.active) {
return;
}
if (!isActiveState(observer.owner.getLifecycle().getCurrentState())) {
return;
}
if (observer.lastVersion >= mVersion) {
return;
}
observer.lastVersion = mVersion;
observer.observer.onChanged((T) mData); //这里的作用是通知对应的UI刷新数据
}
首先当生命周期状态发生改变时activeStateChanged会被调用,过滤掉非active的组件后调用dispatchingValue方法,在这个方法中遍历所以的观察者,发送数据来更新UI。
到此LiveData的整个流程就分析完了。
想要完整代码的请戳这里https://github.com/qiangzier/ORMSample