LiveData源码剖析以及Room对LiveData的支持源码分析

LiveData是一个数据持有者,其本身实现了观察者模式,支持数据监控(被观察),并且可以感知组件的生命周期。
观察者可以指定某一个LifeCycle(activity,fragment)。并对数据进行监听。
如果观察者指定LifeCycle处于Started或者RESUMED状态,LiveData会将观察者视为活动状态,并通知其数据的变化。

实战

先来看一下简单的使用,以下是一个Product列表。
我们首先来看一下数据的处理代码:

public class ProductListViewModel extends AndroidViewModel {

    private final LiveData> mObservableProducts;

    public ProductListViewModel(Application application) {
        super(application);
        final ProductDataRepository repository = new ProductDataRepository();
        mObservableProducts = Transformations.switchMap(repository.isCreatedDatabase(), new Function>>() {
            @Override
            public LiveData> apply(Boolean input) {
                if(!Boolean.TRUE.equals(input)){
                    return ABSENT;
                }else{
                    return repository.getProducts();
                }
            }
        });
    }

    public LiveData> getProducts() {
        return mObservableProducts;
    }
}

代码中将数据源定义成一个LiveData对象,LiveData中持有的是真正需要的数据List

接下来看看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>() {
            @Override
            public void onChanged(@Nullable List 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> queryLiveProducts();
}

2、编译代码,会发现自动生成ProductDao的实现类ProductDao_Impl.java:

public class ProductDao_Impl implements ProductDao {
  ......//省略一大波代码
  @Override
  public LiveData> queryLiveProducts() {
    final String _sql = "select * from products";
    final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
    return new ComputableLiveData>() {
      private Observer _observer;

      @Override
      protected List 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 _result = new ArrayList(_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>对象,那么此对象是个啥玩意呢?让我们找到这个类看看:

public abstract class ComputableLiveData {

    private final LiveData mLiveData;
    ......

    /**
     * Creates a computable live data which is computed when there are active observers.
     * 

* 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() { @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 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. *

* 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() {
            @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 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 _result = new ArrayList(_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>() {
            @Override
            public void onChanged(@Nullable List 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 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, 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

你可能感兴趣的:(LiveData源码剖析以及Room对LiveData的支持源码分析)