1. What is LiveData

An obser-based message subscription/distribution component that relies on Lifecycles to ensure that LiveData data is distributed only to active observers.

2. Use of LiveData

  • Import dependence
Implementation 'androidx. Lifecycle: lifecycle - livedata - KTX: 2.2.0'Copy the code

LiveData is generally distributed as the data of network request in actual combat. LiveData itself is an observer mode. When network request is made in actual combat, LiveData will distribute the data.

MutableLiveData inherits LiveData and is generally used for data distribution. There is another kind of MediatorLiveData that also inherits LiveData, which I’ll talk about later.

  • MutableLiveData use
class MainActivity : AppCompatActivity() { var liveData1: MutableLiveData<Int> = MutableLiveData() var liveData2: MutableLiveData<String> = MutableLiveData() override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState) setContentView(r.layout.activity_main) // Register observer startObserver() // Data has changed liveData1.postValue(1000) liveData2.postValue("33333") } private fun startObserver() { liveData1.observe(this, Observer { Log.i("liveData1",it.toString()) }) liveData2.observe(this, Observer { Log.i("liveData2",it.toString()) }) } }Copy the code

Results:

10 to 17 05:52:45. 645. 4197-4197 / com mg. Axechen. Testdemo I/liveData1: 1000 10 to 17 05:52:45. 645, 4197-4197 / com. Mg. Axechen. Testdemo I/liveData2:33333Copy the code
  • MediatorLiveData

MediatorLiveData can view all MutableLiveData in a unified manner through addSource. Of course, MediatorLiveData itself is also inherited from LiveData and can also be viewed by other observers.


class MainActivity : AppCompatActivity() {
  var liveData1: MutableLiveData<Int> = MutableLiveData()
  var liveData2: MutableLiveData<String> = MutableLiveData()
  var mediatorLiveData: MediatorLiveData<Any> = MediatorLiveData()
  override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_main)
      mediatorLiveData.addSource(liveData1,dataObserver2)
      mediatorLiveData.addSource(liveData2,dataObserver)
      mediatorLiveData.observe(this, Observer {
          Log.i("liveData5",it.toString())
      })
      liveData1.value = 1000
      liveData2.value = "axeChen"
      mediatorLiveData.postValue("xxxx")
  }
  private var dataObserver2 = object :Observer<Int>{
      override fun onChanged(t: Int?) {
          Log.i("liveData4",t.toString())
      }
  }
  private var dataObserver =object :Observer<Any> {
      override fun onChanged(t: Any?) {
          Log.i("liveData3",t.toString())
      }
  }
}
Copy the code

Output result:

10 to 17 06:02:21. 624. 4713-4713 / com mg. Axechen. Testdemo I/liveData4: 1000 10 to 17 06:02:21. 624, 4713-4713 / com. Mg. Axechen. Testdemo I/liveData3: AxeChen 10 to 17 06:02:21. 637. 4713-4713 / com mg. AxeChen. Testdemo I/liveData5: XXXXCopy the code

3. LiveData source code analysis

3.1 Key classes of LiveData

LiveData

public abstract class LiveData<T> {}
Copy the code

The class declaration shows that this is an abstract class that encapsulates the subscribe and unsubscribe methods:

Public void observe(@nonnull LifecycleOwner owner, @nonnull Observer<? super T> observer) {} public void observeForever(@NonNull Observer<? Public void removeObserver(@nonnull final Observer<? super T> observer) {} public void removeObservers(@NonNull final LifecycleOwner owner) {}Copy the code

LifecycleBoundObserver and AlwaysActiveObserver are subclasses of Observerapper, as long as you know that Observerapper is used to distribute data, the specific distribution will be analyzed below.

class LifecycleBoundObserver extends
 ObserverWrapper implements LifecycleEventObserver {} 
 private class AlwaysActiveObserver extends ObserverWrapper {}
Copy the code

LifecycleBoundObserver Lifecycle-safe Observer.

class LifecycleBoundObserver extends
 ObserverWrapper implements LifecycleEventObserver {}
Copy the code

AlwaysActiveObserver A non-lifecycle Observer.

private class AlwaysActiveObserver extends ObserverWrapper {}
Copy the code
3.2. Key methods

The concept of lifecycle security is mentioned above in both subscription methods, but the biggest difference is whether the lifecycle is taken into account when distributing data. There are also different ways to subscribe to life cycle security versus non-life cycle security. The Observer method in LiveData is a subscription with lifecycle safety in mind. The Observer subscribes in a life-cycle safe manner

@MainThread public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? AssertMainThread ("observe"); If (owner.getLifecycle().getCurrentState() == DESTROYED) {// ignore return;  } // 3, wrap LifecycleBoundObserver, LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer); Observer ObserverWrapper existing = mobServers. putIfAbsent(Observer, wrapper); // Observer throws an exception 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); }Copy the code

Take a look at the code for LifecycleBoundObserver. OnStateChanged is the method to distribute the state.

class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver { @NonNull final LifecycleOwner mOwner; LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) { super(observer); mOwner = owner; } @override Boolean shouldBeActive() {// If a state is STARTED or RESUMED, it can be an active state. Return true mowner.getLifecycle ().getCurrentState().isatleast (STARTED); } @Override public void onStateChanged(@NonNull LifecycleOwner source, Lifecycle.State currentState = Lifecycle mOwner.getLifecycle().getCurrentState(); Destory if (currentState == DESTROYED) {removeObserver(mObserver); return; } // 3, Lifecycle.State prevState = null; while (prevState ! = currentState) { prevState = currentState; activeStateChanged(shouldBeActive()); currentState = mOwner.getLifecycle().getCurrentState(); } } @Override boolean isAttachedTo(LifecycleOwner owner) { return mOwner == owner; } @Override void detachObserver() { mOwner.getLifecycle().removeObserver(this); }}Copy the code

In activeStateChanged, pass the state of whether the host is active or not. If it is active then dispatchingValue is called.

void activeStateChanged(boolean newActive) { if (newActive == mActive) { return; } // immediately set active state, so we'd never dispatch anything to inactive // owner mActive = newActive; changeActiveCounter(mActive ? 1:1); If (mActive) {// dispatchingValue(this); }}Copy the code

ObserverForver regardless of lifecycle security

The biggest difference between observerForver and Observer is that LifecycleOwner is not passed in, and life cycle changes are not taken into account. Data callbacks occur whenever data changes.

@MainThread public void observeForever(@NonNull Observer<? AssertMainThread ("observeForever"); AlwaysActiveObserver AlwaysActiveObserver = new AlwaysActiveObserver(observer); Existing = mobServers. putIfAbsent(Observer, wrapper); if (existing instanceof LiveData.LifecycleBoundObserver) { throw new IllegalArgumentException("Cannot add the same observer" + " with different lifecycles"); } if (existing ! = null) { return; } / / 4, the callback data wrapper. ActiveStateChanged (true); }Copy the code
@SuppressWarnings("WeakerAccess") /* synthetic access */ void dispatchingValue(@Nullable ObserverWrapper initiator) { if  (mDispatchingValue) { mDispatchInvalidated = true; return; } mDispatchingValue = true; do { mDispatchInvalidated = false; if (initiator ! = null) {if initiator is not null, let this be called by notice (initiator) when the Observer is registered; initiator = null; } else { for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator = mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {// Let all observers be considered (iterator.next().getvalue ())); if (mDispatchInvalidated) { break; } } } } while (mDispatchInvalidated); mDispatchingValue = false; }Copy the code

The final method for AlwaysActiveObserver to distribute data is notified

private class AlwaysActiveObserver extends ObserverWrapper { AlwaysActiveObserver(Observer<? super T> observer) { super(observer); } @override Boolean shouldBeActive() {// return True; }}Copy the code
private void considerNotify(ObserverWrapper observer) { if (! observer.mActive) { return; } // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet. // // we still first check observer.active to keep it as the entrance for events. So even if // the observer moved to an active state, if we've not received that event, We better not // notify for a more predictable notification order. observer.shouldBeActive()) { observer.activeStateChanged(false); return; If (observer.mLastVersion >= mVersion) {return; } // Synchronize Version observer.mLastVersion = mVersion; / / distribute the data to the observer. MObserver. OnChanged (mData (T)); }Copy the code

As you can see from AlwaysActiveObserver, shouldBeActive() is always true. As soon as the data is available it will be called back. This is pretty clear in the code, so check if you’re active. The data is then distributed.

3.3. Remove a subscription

So this is removing the subscription

@MainThread public void removeObserver(@NonNull final Observer<? super T> observer) { assertMainThread("removeObserver"); ObserverWrapper removed = mObservers.remove(observer); if (removed == null) { return; } removed.detachObserver(); removed.activeStateChanged(false); } @MainThread public void removeObservers(@NonNull final LifecycleOwner owner) { assertMainThread("removeObservers"); for (Map.Entry<Observer<? super T>, ObserverWrapper> entry : mObservers) { if (entry.getValue().isAttachedTo(owner)) { removeObserver(entry.getKey()); }}}Copy the code
3.4, PostValue(), setValue()

As you can see from the first example, if these two methods are called, liveData.observer{} can observe the change in value and get the new value. These two methods are methods that update LiveData values.

protected void postValue(T value) { boolean postTask; synchronized (mDataLock) { postTask = mPendingData == NOT_SET; mPendingData = value; } if (! postTask) { return; } ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable); }Copy the code
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}
Copy the code

The difference between the two:

  • SetValue can only be called from the main thread.
  • PostValue can be called in child threads and has the function of synchronization lock.
  • 3, postValue multiple calls are valid only for the last value.

4, summarize

When using LiveData, it will distribute data according to whether the host is active or not, so as to reduce the waste of resources when processing data because activities and fragments are invisible. Try to use safe subscription and postValue methods when using LiveData.