LiveData

define

  • An observable data store class that literally translates as real-time data (a data holder that wraps a layer around the source data, which can be observed by the Observer when the data is updated);
  • Lifecycle awareness to ensure that LiveData only updates application component observers that are in an active lifecycle state;

The characteristics of

  1. Ensure that the interface conforms to data state: When the lifecycle state changes, LiveData notifies the Observer that the interface can be updated in the Observer. Instead of refreshing the screen every time the data changes, the observer can refresh the screen every time the lifecycle state changes.
  2. Memory leaks will not occur: The Observer will remove automatically after LifecycleOwner changes to DESTROYED;
  3. Does not crash when the Activity stops: If the LifecycleOwner life cycle is inactive, it does not receive any LiveData events;
  4. No need to manually remove observation: Life cycle can be automatically managed
  5. Data is always up to date: If LifecycleOwner is inactive when data is updated, it receives the latest data when it becomes active;

Simple use of LiveData

class LiveDataActivity : AppCompatActivity() { private lateinit var mMutableLiveData: MutableLiveData<String> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_live_data) //1. Create LiveData instance and specify source data type mMutableLiveData = MutableLiveData<String>() //2. Create an Observer instance and implement the onChanged() method, Used to receive the source data changes and refresh the UI val observer = observer < String > {LjyLogUtil. D (" mMutableLiveData. Observe. OnChanged: ${it} ")} / / 3 The LiveData instance adds an observer observer using the observe() method, LifecycleOwner mmutableliveData.observe (this, observer) //4 Change data in LiveData //4.1 If you want to change the values stored in the LiveData object before it is distributed to the observer, Map () val mapLiveData = doubling. Map (mMutableLiveData, Function { it + "_LJY" }) mapLiveData.observe(this, The Observer {LjyLogUtil. D (" mapLiveData. Observe. OnChanged: ${it} ")}) / / 4.2 Transformations. SwitchMap (), switch to monitor val liveData0 =  MutableLiveData<Boolean>() val liveData1 = MutableLiveData<String>() val liveData2 = MutableLiveData<String>() val switchMapLiveData = Transformations.switchMap(liveData0, Function { if (it) { liveData1 } else { liveData2 } }) switchMapLiveData.observe(this, Observer { LjyLogUtil.d("switchMapLiveData.observe.onChanged:${it}") }) liveData1.value = "123" liveData2.value = "456" liveData0.value = false //5. //MediatorLiveData inherits from mutableLiveData, which combines multiple LiveData sources, The purpose of a component to monitor multiple LiveData data changes val mediatorLiveData = mediatorLiveData < String > () mediatorLiveData. AddSource (liveData0, Observer { LjyLogUtil.d("mediatorLiveData.addSource(liveData0):$it") }) mediatorLiveData.addSource(liveData1, Observer { LjyLogUtil.d("mediatorLiveData.addSource(liveData1):$it") }) mediatorLiveData.addSource(liveData2, Observer { LjyLogUtil.d("mediatorLiveData.addSource(liveData2):$it") }) mediatorLiveData.observe(this, Observer { LjyLogUtil.d("mediatorLiveData.observe:$it") }) liveData1.value = "321" liveData2.value = "654" //6. LiveData instance updates source data with setValue() (main thread) /postValue() (child thread) ljylogutil.d ("onCreate") mmutabLeliveData.value = "value=onCreate" GlobalScope.launch { liveData0.postValue(true) delay(2000) mMutableLiveData.postValue("value=GlobalScope") liveData0.postValue(false) } } override fun onStart() { super.onStart() LjyLogUtil.d("onStart") mMutableLiveData.value =  "value=onStart" } override fun onResume() { super.onResume() LjyLogUtil.d("onResume") mMutableLiveData.value = "value=onResume" } override fun onPause() { super.onPause() LjyLogUtil.d("onPause") mMutableLiveData.value = "value=onPause" } override fun onStop() { super.onStop() LjyLogUtil.d("onStop") mMutableLiveData.value = "value=onStop" } override fun onDestroy() { super.onDestroy() LjyLogUtil.d("onDestroy") mMutableLiveData.value = "value=onDestroy" } }Copy the code
  • The above update data source methods setValue() (main thread) /postValue() (child thread), mainly to distinguish the call scenario, are coded as follows
@MainThread protected void setValue(T value) { assertMainThread("setValue"); mVersion++; mData = value; dispatchingValue(null); } protected void postValue(T value) { boolean postTask; synchronized (mDataLock) { postTask = mPendingData == NOT_SET; mPendingData = value; } if (! postTask) { return; } ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable); } // the postValue method throws the Runable object mPostValueRunnable to the main thread, SetValue () private final Runnable mPostValueRunnable = new Runnable() {@suppressWarnings ("unchecked") @Override public void run() { Object newValue; synchronized (mDataLock) { newValue = mPendingData; mPendingData = NOT_SET; } setValue((T) newValue); // also go to setValue method}};Copy the code

Extend the LiveData object

//1. Class MyLiveData(context: context) : LiveData<String>() { init { LocationUtil.getInstance().getLocation(context) } companion object { var instance: MyLiveData? = null fun get(context: Context): MyLiveData? { if (instance == null) { instance = MyLiveData(context) } return instance } } val callback = LocationUtil.CallBack() { Override fun onActive() {super.onactive () override fun onActive() {super.onactive (); LjyLogUtil.d("MyLiveData.onActive") LocationUtil.getInstance().setCallBack(callback) } override fun onInactive() { super.onInactive() LjyLogUtil.d("MyLiveData.onInactive") LocationUtil.getInstance().removeCallBack() } } //2. Use: MyLiveData. Get (this)? .observe(this, Observer { LjyLogUtil.d("LiveDataActivity:$it") })Copy the code
  • SetCallBack is called when the LiveData object has an Active observer. OnInactive is called when the LiveData object has no Active observer. CallBack onCall() is bound to value = it, so observe() can observe real-time data.

LiveData principle

  • After the above use, we find that LiveData and RxJava are very similar, both use the observer mode, the difference is that LiveData does not notify all observers, but only Active state observers, so how to do this?

LiveData observes the component life cycle

  • We know that LiveData registers observers with Observe (), so use this as an entry point to see how the code works
  • Observe () returns getCurrentState() == DESTROYED. The component is not allowed to register as an observer if it is in the state of DESTROYED
@MainThread public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { assertMainThread("observe"); if (owner.getLifecycle().getCurrentState() == DESTROYED) { // ignore return; } // Owner, observer wrapper class LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer); // Store the Observer and LifecycleBoundObserver to SafeIterableMap< observer <? super T>, ObserverWrapper> ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); if (existing ! = null && ! IsAttachedTo (owner)) {// Cannot add the same observer but different LifecycleOwner throw new IllegalArgumentException("Cannot add the same observer" + " with different lifecycles"); } // return if (existing! = null) { return; } // Add LifecycleBoundObserver to Lifecycle to complete the registration of owner.getLifecycle().addobServer (wrapper); } // In addition to adding an Observer using the observe() method, you can also use the observeForever(Observer) method to register // unassociated LifecycleOwner observers. In this case, the observer is seen to be active at all times; @MainThread public void observeForever(@NonNull Observer<? super T> observer) { assertMainThread("observeForever"); AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer); ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); if (existing ! = null && existing instanceof LiveData.LifecycleBoundObserver) { throw new IllegalArgumentException("Cannot add the same  observer" + " with different lifecycles"); } if (existing ! = null) { return; } wrapper.activeStateChanged(true); } private class AlwaysActiveObserver extends ObserverWrapper { AlwaysActiveObserver(Observer<? super T> observer) { super(observer); } @Override boolean shouldBeActive() { return true; }}Copy the code
  • Take a look at LifecycleBoundObserver, which is the inner class of LiveData
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver { @NonNull final LifecycleOwner  mOwner; LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) { super(observer); mOwner = owner; } @override Boolean shouldBeActive() {return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED); } // When the component state changes, OnStateChanged @override public void onStateChanged(LifecycleOwner source, Lifecycle. If (mowner.getLifecycle ().getCurrentState() == DESTROYED) { Remove the observer removeObserver (mObserver); return; } // Call the parent method activeStateChanged(shouldBeActive()); } @Override boolean isAttachedTo(LifecycleOwner owner) { return mOwner == owner; } @Override void detachObserver() { mOwner.getLifecycle().removeObserver(this); }}Copy the code
  • OnStateChanged () is called when the component state changes above. ActiveStateChanged () of the parent class is called within onStateChanged, with the following code: As you can see, activeStateChanged calls back to the onActive method and onInactive method, which are used to extend the LiveData object, based on the Active state and number of components in the Active state;
private abstract class ObserverWrapper { final Observer<? super T> mObserver; boolean mActive; int mLastVersion = START_VERSION; ObserverWrapper(Observer<? super T> observer) { mObserver = observer; } abstract boolean shouldBeActive(); boolean isAttachedTo(LifecycleOwner owner) { return false; } void detachObserver() { } void activeStateChanged(boolean newActive) { if (newActive == mActive) { return; } // immediately set active state, so we'd never dispatch anything to inactive // owner mActive = newActive; boolean wasInactive = LiveData.this.mActiveCount == 0; LiveData.this.mActiveCount += mActive ? 1:1; if (wasInactive && mActive) { onActive(); } if (LiveData.this.mActiveCount == 0 && ! mActive) { onInactive(); } if (mActive) { dispatchingValue(this); }}}Copy the code
  • At the end of the above code, if the state is Active, dispatchingValue() is called and itself passed in, as follows
Void dispatchingValue(@nullable ObserverWrapper initiator) {if (mDispatchingValue) { MDispatchInvalidated = true; return; } mDispatchingValue = true; do { mDispatchInvalidated = false; if (initiator ! = null) { considerNotify(initiator); initiator = null; } else { for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator = mObservers.iteratorWithAdditions(); iterator.hasNext(); ) { considerNotify(iterator.next().getValue()); if (mDispatchInvalidated) { break; } } } } while (mDispatchInvalidated); mDispatchingValue = false; }Copy the code
  • The above distribution method eventually calls considerNotify(), whose code is as follows,
private void considerNotify(ObserverWrapper observer) { if (! observer.mActive) { return; } if (! observer.shouldBeActive()) { observer.activeStateChanged(false); return; } if (observer.mLastVersion >= mVersion) { return; } observer.mLastVersion = mVersion; //noinspection unchecked observer.mObserver.onChanged((T) mData); }Copy the code
  • As you can see, if the conditions are met, the onChanged method of the Observer is called, which is a callback to the Observe method using LiveData

My name is Jinyang. If you want to learn more about jinyang, please pay attention to the wechat public number “Jinyang said” to receive my latest articles