LiveData是一個(gè)數(shù)據(jù)持有者,其本身實(shí)現(xiàn)了觀察者模式绽乔,支持?jǐn)?shù)據(jù)監(jiān)控(被觀察),并且可以感知組件的生命周期碳褒。
觀察者可以指定某一個(gè)LifeCycle(activity折砸,fragment)。并對(duì)數(shù)據(jù)進(jìn)行監(jiān)聽沙峻。
如果觀察者指定LifeCycle處于Started或者RESUMED狀態(tài)睦授,LiveData會(huì)將觀察者視為活動(dòng)狀態(tài),并通知其數(shù)據(jù)的變化专酗。
實(shí)戰(zhàn)
先來看一下簡單的使用睹逃,以下是一個(gè)Product列表。
我們首先來看一下數(shù)據(jù)的處理代碼:
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;
}
}
代碼中將數(shù)據(jù)源定義成一個(gè)LiveData對(duì)象祷肯,LiveData中持有的是真正需要的數(shù)據(jù)List<ProductEntity>沉填。
接下來看看UI層是如何使用的,請(qǐng)看下面代碼:
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(...)就是訂閱數(shù)據(jù)佑笋。observe的第一個(gè)參數(shù)是LifeCycleOwner翼闹,即和生命周期綁定。
而ProductListFragment是繼承自LifecycleFragment蒋纬,LifecycleFragment就是一個(gè)LifecycleOwner,因此此處傳入this猎荠。第二個(gè)參數(shù)是一個(gè)觀察者坚弱,當(dāng)數(shù)據(jù)發(fā)生變化是會(huì)通過該觀察者來刷新。
下面通過分析Room對(duì)LiveData的支持來分析LiveData的工作原理
下面我們先看看從數(shù)據(jù)庫中獲取所有product的代碼:
1关摇、首先定義獲取數(shù)據(jù)的dao接口荒叶,返回類型為LiveData
@Dao
public interface ProductDao {
@Query("select * from products")
LiveData<List<ProductEntity>> queryLiveProducts();
}
2、編譯代碼输虱,會(huì)發(fā)現(xiàn)自動(dòng)生成ProductDao的實(shí)現(xiàn)類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();
}
...... //省略一大波代碼
}
這里我們只關(guān)心具體方法的實(shí)現(xiàn)些楣,可以看到生成的代碼中返回的是一個(gè)ComputableLiveData<List<ProductEntity>>對(duì)象,那么此對(duì)象是個(gè)啥玩意呢宪睹?讓我們找到這個(gè)類看看:
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();
}
可以看出這個(gè)類其實(shí)就是對(duì)Live的一層包裝愁茁,并且處理了線程切換相關(guān)的東西。
首先在初始化類時(shí)會(huì)初始化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);
}
};
并且如果當(dāng)前組件處于active狀態(tài)時(shí)會(huì)執(zhí)行mRefreshRunnable亭病。而這個(gè)runnable中的代碼如下:
T value = null;
while (mInvalid.compareAndSet(true, false)) {
computed = true;
value = compute();
}
if (computed) {
mLiveData.postValue(value);
}
這段代碼實(shí)現(xiàn)了兩個(gè)功能鹅很。
1、獲取需要的數(shù)據(jù)value = compute()
,
2罪帖、刷新數(shù)據(jù)mLiveData.postValue(value)
從上面代碼中我們看到這個(gè)compute是個(gè)抽象方法促煮,那么他是在哪里實(shí)現(xiàn)的呢?讓我們回到Dao的實(shí)現(xiàn)類里看看胸蛛,具體實(shí)現(xiàn)代碼如下:
@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();
}
}
可以看到這里是從數(shù)據(jù)庫中查詢數(shù)據(jù)并返回一個(gè)List對(duì)象污茵。至此回去數(shù)據(jù)的流程大致走了一遍,接下來就是如何訂閱的事情了葬项。
訂閱數(shù)據(jù)
這里采用了MVVM模式泞当,ViewModel將數(shù)據(jù)發(fā)送到對(duì)應(yīng)的UI界面來更新UI,這里拋開MVVM框架只看LiveData是如何更新UI的民珍。
要想更新UI首先需要訂閱對(duì)應(yīng)的數(shù)據(jù)襟士,也就是liveData。所以我們需要在Fragment/Activity中來訂閱數(shù)據(jù)嚷量,代碼如下:
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()返回的是一個(gè)LiveData對(duì)象陋桂,通過調(diào)用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蝶溶、可以發(fā)現(xiàn)訂閱是首先判斷當(dāng)前的狀態(tài)嗜历,如果是destroyed時(shí)直接返回。
2抖所、將傳入的observer放到一個(gè)Map中梨州。
3、將當(dāng)前的頁面加入生命周期的觀察者map中田轧,讓其可被觀察暴匠。
這樣當(dāng)頁面的生命周期狀態(tài)發(fā)生變化時(shí)會(huì)通知到LiveData,LiveData再去遍歷所以的observer復(fù)合條件的發(fā)送數(shù)據(jù)更新傻粘。代碼如下:
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); //這里的作用是通知對(duì)應(yīng)的UI刷新數(shù)據(jù)
}
首先當(dāng)生命周期狀態(tài)發(fā)生改變時(shí)activeStateChanged會(huì)被調(diào)用每窖,過濾掉非active的組件后調(diào)用dispatchingValue方法帮掉,在這個(gè)方法中遍歷所以的觀察者,發(fā)送數(shù)據(jù)來更新UI窒典。
到此LiveData的整個(gè)流程就分析完了蟆炊。
想要完整代碼的請(qǐng)戳這里https://github.com/qiangzier/ORMSample