LiveData源碼剖析以及Room對LiveData的支持源碼分析

LiveData是一個(gè)數(shù)據(jù)持有者,其本身實(shí)現(xiàn)了觀察者模式,支持?jǐn)?shù)據(jù)監(jiān)控(被觀察),并且可以感知組件的生命周期。
觀察者可以指定某一個(gè)LifeCycle(activity,fragment)。并對數(shù)據(jù)進(jìn)行監(jiān)聽。
如果觀察者指定LifeCycle處于Started或者RESUMED狀態(tài),LiveData會將觀察者視為活動狀態(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對象,LiveData中持有的是真正需要的數(shù)據(jù)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(...)就是訂閱數(shù)據(jù)。observe的第一個(gè)參數(shù)是LifeCycleOwner,即和生命周期綁定。
而ProductListFragment是繼承自LifecycleFragment,LifecycleFragment就是一個(gè)LifecycleOwner,因此此處傳入this。第二個(gè)參數(shù)是一個(gè)觀察者,當(dāng)數(shù)據(jù)發(fā)生變化是會通過該觀察者來刷新。

下面通過分析Room對LiveData的支持來分析LiveData的工作原理

下面我們先看看從數(shù)據(jù)庫中獲取所有product的代碼:

1、首先定義獲取數(shù)據(jù)的dao接口,返回類型為LiveData

@Dao
public interface ProductDao {
    @Query("select * from products")
    LiveData<List<ProductEntity>> queryLiveProducts();
}

2、編譯代碼,會發(fā)現(xiàn)自動生成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>>對象,那么此對象是個(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í)就是對Live的一層包裝,并且處理了線程切換相關(guān)的東西。
首先在初始化類時(shí)會初始化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í)會執(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對象。至此回去數(shù)據(jù)的流程大致走了一遍,接下來就是如何訂閱的事情了。

訂閱數(shù)據(jù)

這里采用了MVVM模式,ViewModel將數(shù)據(jù)發(fā)送到對應(yīng)的UI界面來更新UI,這里拋開MVVM框架只看LiveData是如何更新UI的。

要想更新UI首先需要訂閱對應(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對象,通過調(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í)會通知到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);   //這里的作用是通知對應(yīng)的UI刷新數(shù)據(jù)
}

首先當(dāng)生命周期狀態(tài)發(fā)生改變時(shí)activeStateChanged會被調(diào)用,過濾掉非active的組件后調(diào)用dispatchingValue方法,在這個(gè)方法中遍歷所以的觀察者,發(fā)送數(shù)據(jù)來更新UI。

到此LiveData的整個(gè)流程就分析完了。

想要完整代碼的請戳這里https://github.com/qiangzier/ORMSample

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容