Android Jetpack's LiveData source code analysis

LiveData is an observable data storage class. Unlike regular observable classes, LiveData is lifecycle aware, meaning it follows the lifecycle of other application components such as activity, fragment or service. This awareness ensures that LiveData only updates app component observers that are in an active lifecycle state.

LiveData considers an observer (represented by the Observer class) to be active if its lifecycle is in the STARTED or RESUMED state. LiveData will only notify active observers of updates. Inactive observers registered to observe LiveData objects are not notified of changes.

You can register observers paired with objects that implement the LifecycleOwner interface. With this relationship in place, the observer can be removed when the state of the corresponding Lifecycle object becomes DESTROYED. This is especially useful for activities and fragments, since they can safely observe LiveData objects without worrying about leaks (the system immediately unsubscribes activities and fragments when their lifecycle is destroyed).

Advantages of LiveData:

  • Make sure the interface conforms to the data state
  • no memory leaks
  • No crashes due to Activity stopping
  • No more manual handling of lifecycles
  • Data is always up to date
  • Appropriate configuration changes
  • Shared resources .

The above content is from the official website, official website address

insert image description here
Through the previous blog: Simple use of LiveData . We learned about the basic usage of LiveData. review here

LiveData is simple and practical (generally it is practical with ViewModel)


public class LiveDataActivity extends AppCompatActivity {
    private TextView mTextContent;
    //使用LiveData
    private MutableLiveData<String> contentLiveData = new MutableLiveData<>();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_livedata_test);
        mTextContent = findViewById(R.id.tv_content);
        //设置 观察者
        contentLiveData.observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                mTextContent.setText(s);
            }
        });
        //点击按钮,改变内容
        findViewById(R.id.btn_livedata_change).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                contentLiveData.setValue("内容改变了");
            }
        });
    }
}


In the following source code analysis, in some cases, Lifecycle() will be designed to monitor the life cycle. If you are interested, you can take a look at: The use and source code analysis of Lifecycle in Android Jetpack

Next, we analyze through the steps used above. What operations are performed on the LiveData content

1. Set the observe() method

Add observers, and we don't need relations, removals, and memory leaks

Look at the source code below


    private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
            new SafeIterableMap<>();
		...
	@MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");

		//owner是Activity已经实现的(Lifecycle文章有说)
		//如果owner的生命周期已经结束的话,直接返回。避免了内存泄露,甚至Crash
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
		//wrapper包装类。里面主要是一些生命周期及版本的判断
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);

		//这里,我们看到添加观察者的时候。是把观察者做key,放到了一个Map里面
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
		//这里跟我们添加Lifecycle()一样,可以让wrapper监听owner生命周期,做一些判断
        owner.getLifecycle().addObserver(wrapper);
    }

Seeing this, it is actually very simple to add an observer. In fact, a Map is created in LiveData and the observer is stored in it.

The value of Map is an encapsulation class that includes owner (here is Activity, easy to understand) and observer.

Second, analyze the content changed by set/postValue()

Next, let's take a look at how LiveData's setValue() method passes the value

public class MutableLiveData<T> extends LiveData<T> {

    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}


Here super.setValue() is called to continue reading

    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
		//这里的版本,后面会说
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

2 things are done here:

1. Assign the value to mData
2. Call dispatchingValue(null);

let's see next

  void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
			//initiator这里通过上面知道,传递的是null。所以,走else
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
				//把所有观察者的Map,通过迭代器遍历
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }


Here, we can see that the dispatchingValue() method is to traverse the Map where the observer is located, and then call the considerNotify() method.

Look at the considerNotify() method

 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.
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
		//通过上面一系列的判断,最终调用了观察者的onChanged方法。
        observer.mObserver.onChanged((T) mData);
    }

Here, we can see that through a series of life cycle judgments and version judgments, the onChange() method of the observer is finally called.
At this point, we have gone through all the calling processes.

The whole process of postValue is similar to setValue. It's just that it switched to the main thread through the Handler later

insert image description here

[Unfinished]
There is one thing above that we didn't say, that is, the mLastVersion of the observer and the mVersion of the data. This is also the cause of sticky data. However, it is different from EventBus in that EventBus is a switch that provides sticky data, but it does not.

Problem: LiveData's data backflow/sticky data problem.

Scenario: (list – details (modify data) – go back and click on other lists – enter details again) (use ShareViewModel)

SingleLiveEvent (resolve one event, only consume once), when multiple observers are registered, only one will be received, which is very error-prone.

UnPeek-LiveData Solution

Guess you like

Origin blog.csdn.net/ecliujianbo/article/details/128012255