LiveData一般是和 ViewModel 配合使用的,但是本文就以單獨使用 LiveData 作為例子單獨使用,這樣可以只關注 LiveData 而不被其他所干擾。
本文整體流程:首先要知道什么是 LiveData,然后演示一個例子,來看看 LiveData 是怎么使用的,接著提出問題為什么是這樣的,最后讀源碼來解釋原因!
LiveData 的源碼比較簡單,底層依賴了 Lifecycle,所以懂 Lifecycle 的源碼是關鍵,我之前寫過一篇
Android Jetpack組件Lifecycle基本使用和原理分析 最好是先看這篇文章,才能更好的理解 LiveData。
1.什么是 LiveData
LiveData是一種可觀察的數據存儲器類。與常規的可觀察類不同,LiveData 具有生命周期感知能力,意指它遵循其他應用組件(如 Activity、Fragment 或 Service)的生命周期。這種感知能力可確保 LiveData 僅更新處于活躍生命周期狀態的應用組件觀察者。
2.LiveData基礎使用的例子
這個例子,是點擊按鈕通過 LiveData 來更新 TextView 的內容
如圖:
[圖片上傳失敗...(image-90c8e1-1606802615929)]
點擊按鈕后
[圖片上傳失敗...(image-cc2c98-1606802615929)]
具體代碼
class LiveDataActivity : BaseActivity() {
private val mContent = MutableLiveData<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_live_data)
btnUpdate.setOnClickListener {
mContent.value = "最新值是:Update"
}
mContent.observe(this, Observer { content ->
tvContent.text = content
})
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tvContent"
android:layout_width="0dp"
android:text="Hello World"
android:layout_height="wrap_content"
android:textColor="#f00"
android:gravity="center"
android:textSize="24sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btnUpdate"
android:layout_width="wrap_content"
android:text="Update"
android:padding="5dp"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="18sp"
android:layout_marginTop="20dp"
android:textAllCaps="false"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tvContent" />
</androidx.constraintlayout.widget.ConstraintLayout>
默認TextView展示的是: Hello World,點擊按鈕后展示的是:“最新值是:Update” 。這個就是LiveData 的簡單使用。
3.拋出問題
為什么LiveData的工作機制是這樣的
- LiveData 是怎么回調的?
- LiveData 為什么可以感知生命周期?
- LiveData 可以感知生命周期,有什么用,或者說有什么優勢?
- LiveData 為什么只會將更新通知給活躍的觀察者。非活躍觀察者不會收到更改通知?
- LiveData此外還提供了observerForever()方法,所有生命周期事件都能通知到,怎么做到的?
解析來通過分析源碼,來尋找答案。文章最后我會解釋這些問題的,做一個統一的總結。
4.源碼分析前的準備工作
我需要了解幾個類,來對接下來的源碼分析做一個鋪墊。
先看之前例子中的代碼
class LiveDataActivity : BaseActivity() {
private val mContent = MutableLiveData<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mContent.observe(this, Observer { content ->
tvContent.text = content
})
}
}
只貼出了主要代碼,我們來看下主要的類以及方法,方法參數
- 聲明了一個MutableLiveData對象
- 調用了MutableLiveData的observe方法
- observe方法中 傳入 this 和 Observer
- this 指的是LiveDataActivity對象,其實一個是一個LifecycleOwner。Observer是一個接口
來分別看下具體內容。
4.1.MutableLiveData類
public class MutableLiveData<T> extends LiveData<T> {
public MutableLiveData(T value) {
super(value);
}
public MutableLiveData() {
super();
}
@Override
public void postValue(T value) {
super.postValue(value);
}
@Override
public void setValue(T value) {
super.setValue(value);
}
}
- 繼承了LiveData是一個可變的LiveData
- 是一個被觀察者,是一個數據持有者
- 提供了 setValue 和 postValue方法,其中postValue可以在子線程調用
- postValue方法,我們下面會具體分析
4.2.MutableLiveData的observe方法參數中的 this
當前 Activity 的對象,本質上是一個LifecycleOwner 我在這篇 Android Jetpack組件Lifecycle基本使用和原理分析中有分析過,它的源碼。
public interface LifecycleOwner {
@NonNull
Lifecycle getLifecycle();
}
4.3MutableLiveData的observe方法參數中的 Observer
public interface Observer<T> {
/**
* Called when the data is changed.
* @param t The new data
*/
void onChanged(T t);
}
- Observer是一個觀察者
- Observer中有一個回調方法,在 LiveData 數據改變時會回調此方法
通過以上簡單分析,我們大概了解了這個幾個類的作用,接下來我們一步一步看源碼,來從源碼中解決我們在第 3 節提出的問題。
5.源碼分析
首先我們上面示例中的 LiveData.observe()方法開始。
//LiveDataActivity.kt
private val mContent = MutableLiveData<String>()
mContent.observe(this, Observer { content ->
tvContent.text = content
})
我們點進observe方法中去它的源碼。
6.LiveData類
在LiveData的observe方法中
//LiveData.java
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
//1
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
//2
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
//3
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
//4
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
//5
owner.getLifecycle().addObserver(wrapper);
}
注釋 1:首先會通過LifecycleOwner獲取Lifecycle對象然后獲取Lifecycle 的State,如果是DESTROYED直接 return 了。忽略這次訂閱
注釋 2 :把LifecycleOwner和Observer包裝成LifecycleBoundObserver對象,至于為什么包裝成這個對象,我們下面具體講,而且這個是重點。
注釋 3:把觀察者存到 Map 中
注釋 4:之前添加過LifecycleBoundObserver,并且LifecycleOwner不是同一個,就拋異常
注釋 5:通過Lifecycle和添加 LifecycleBoundObserver觀察者,形成訂閱關系
總結:
到現在,我們知道了LiveData的observe方法中會判斷 Lifecycle 的生命周期,會把LifecycleOwner和Observer包裝成LifecycleBoundObserver對象,然后 Lifecycle().addObserver(wrapper)
Lifecycle 這個被觀察者會在合適的實際通知觀察者的回調方法。
等等,什么時候通知,咋通知的呢?這個具體流程是啥呢?
回個神,我再貼下開始的示例代碼。
class LiveDataActivity : BaseActivity() {
private val mContent = MutableLiveData<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_live_data)
//1
btnUpdate.setOnClickListener {
mContent.value = "最新值是:Update"
}
mContent.observe(this, Observer { content ->
tvContent.text = content
})
}
}
在點擊按鈕的時候 LiveData會調用setValue方法,來更新最新的值,這時候我們的觀察者Observer就會收到回調,來更新 TextView。
所以接下來我們先看下 LiveData的setValue方法做了什么,LiveData還有一個postValue方法,我們也一并分析一下。
7.LiveData的setValue方法和postValue方法
7.1.先看setValue方法
//LiveData.java
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);//1
}
調用了dispatchingValue方法,繼續跟代碼
//LiveData.java
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
//1
considerNotify(initiator);
initiator = null;
} else {
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
//2
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
不管如何判斷,都是調用了considerNotify()
方法
//LiveData.java
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);//1
}
最終調用了observer.mObserver.onChanged((T) mData)
方法,這個observer.mObserver就是我們的 Observer接口,然后調用它的onChanged
方法。
到現在整個被觀察者數據更新通知觀察者這個流程就通了。
7.2.然后再看下postValue方法
子線程發送消息通知更新 UI,嗯?Handler 的味道,我們具體看下代碼
//LiveData.java
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);//1
}
可以看到一行關鍵代碼ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
點 **postToMainThread **方法進去看下
//ArchTaskExecutor.java
private TaskExecutor mDelegate;
@Override
public void postToMainThread(Runnable runnable) {
mDelegate.postToMainThread(runnable);//1
}
看到 mDelegate 是 TaskExecutor對象,現在目標是看下 mDelegate 的具體實例對象是誰
//ArchTaskExecutor.java
private ArchTaskExecutor() {
mDefaultTaskExecutor = new DefaultTaskExecutor();
mDelegate = mDefaultTaskExecutor;//1
}
好的,目前的重點是看下DefaultTaskExecutor是個啥,然后看它的postToMainThread
方法
//DefaultTaskExecutor.java
private volatile Handler mMainHandler;
@Override
public void postToMainThread(Runnable runnable) {
if (mMainHandler == null) {
synchronized (mLock) {
if (mMainHandler == null) {
mMainHandler = createAsync(Looper.getMainLooper());//1
}
}
}
mMainHandler.post(runnable);//2
}
注釋 1:實例了一個 Handler 對象,注意構造參數 Looper.getMainLooper()是主線的 Looper。那么就可做到線程切換了。
注釋 2:調用post 方法。
下面看下這個 Runnable
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
這里面的方法參數是mPostValueRunnable是個 Runnable,我們看下代碼
//LiveData.java
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);//1
}
};
注意:postValue方法其實最終調用也是setValue方法,然后和setValue方法走的流程就是一樣的了,這個上面已經分析過了。詳情請看 7.1 小節
但是我們還不知道ObserverWrapper是啥,好那么接下來,我們的重點來了
我們要詳細看一下LifecycleBoundObserver類了,它包裝了LifecycleOwner和Observer,這就是接下來的重點內容了。
8.LifecycleBoundObserver類
再貼下一下代碼,當LiveData調用observe方法時
//LiveData.java
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
//1
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
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;
}
owner.getLifecycle().addObserver(wrapper);
}
注釋 1 :用LifecycleBoundObserver對LifecycleOwner 和 Observer進行了包裝
8.1.來看下LifecycleBoundObserver類,它是LiveData的內部類
//LiveData.java
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
}
兩個參數,一個 owner被成員變量mOwner存儲,observer參數被ObserverWrapper的 mObserver存儲。
- LifecycleEventObserver是LifecycleObserver的子接口里面有一個onStateChanged方法,這個方法會在 Activity、Fragment 生命周期回調時調用,如果這么說不明看下這篇文章Android Jetpack組件Lifecycle基本使用和原理分析
- ObserverWrapper 是Observer包裝類
我們接下來看下ObserverWrapper類
8.2.ObserverWrapper類
private abstract class ObserverWrapper {
final Observer<? super T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION;
//1
ObserverWrapper(Observer<? super T> observer) {
mObserver = observer;
}
//2
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) {
//3
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
//4
onInactive();
}
if (mActive) {
//5
dispatchingValue(this);
}
}
}
注:活躍狀態指的是 Activity、Fragment 等生命周期處于活躍狀態
注釋 1:獲取了我們的 Observer 對象,存儲在 成員變量mObserver身上
注釋 2:抽象方法,當前是否是活躍的狀態
注釋 3:可以繼承 LiveData 來達到擴展 LiveData 的目標,并且是在活躍的狀態調用
注釋 4:可以繼承 LiveData 來達到擴展 LiveData 的目標,并且是在非活躍的狀態調用
注釋 5:活躍狀態,發送最新的值,來達到通知的作用, dispatchingValue(this)方法咋這么眼熟,對之前在 LiveData 調用 setValue 方法時,最終也會調用到此方法。那ObserverWrapper類中的dispatchingValue這個方法是在activeStateChanged
方法中調用,那activeStateChanged
啥時候調用呢?
我來看下ObserverWrapper的子類也就是最重要的那個類LifecycleBoundObserver,現在看它的完整代碼
8.3.LifecycleBoundObserver完整代碼
這里是關鍵代碼了
//LiveData.java
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() {
//1
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
//2
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
//3
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
//4
mOwner.getLifecycle().removeObserver(this);
}
}
注釋 1:判斷當前的 Lifecycle 的生命周期是否是活躍狀態,會在回調觀察則 Observer 的時候進行判斷,只有在活躍狀態,才會回調觀察者Observer的onChanged方法。
直接就回答了我們上面的這個問題LiveData 為什么只會將更新通知給活躍的觀察者。非活躍觀察者不會收到更改通知? 首先會通過LifecycleOwner獲取Lifecycle對象然后獲取Lifecycle 的State,并且狀態大于STARTED。這里的State是和 Activity、Fragment 的生命周期是對應的,具體看這篇文章 Android Jetpack組件Lifecycle基本使用和原理分析 的第4.4小節,有詳細的解釋。
注釋 2:onStateChanged每次 Activity、Fragment的生命周期回調的時候,都會走這個方法。
獲取Lifecycle對象然后獲取Lifecycle 的State如果為DESTROYED則移除觀察者,在 Activity、Fragment的生命周期走到 onDestroy 的時候,就會取消訂閱,避免內存泄漏。
注釋 3:調用父類ObserverWrapper 的activeStateChanged
方法,層層調用到觀察者Observer的onChanged方法。(自己看下源碼一目了然)
重點來了:在LiveData 調用setValue
方法時,會回調觀察者Observer的onChanged方法,Activity、Fragment的生命周期變化的時候且為活躍也會回調觀察者Observer的onChanged方法。這就是為什么你在ActivityB頁面,調用setValue
方法,更新了value,在ActivityA 重新獲取焦點時也同樣會收到這個最新的值。
注釋 4:移除觀察者Observer,解除訂閱關系。
到這個時候,LiveData 的 observer方法
、setValue
方法,整個流程就分析完了。
如果我們想不管生命周期,而是想在setValue的值發生改變的時候就能接受到通知,LiveData 還提供了一個observeForever
方法
class LiveDataActivity : BaseActivity() {
private val mContent = MutableLiveData<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_live_data)
btnUpdate.setOnClickListener {
mContent.value = "最新值是:Update"
}
//只要在值發生改變時,就能接收到
mContent.observeForever { content ->
tvContent.text = content
}
}
}
8.4LiveData 的observeForever方法
這個方法比observe方法少一個LifecycleOwner參數,為啥呢?因為這個方法不需要感知生命周期,需要在setValue 值更新時立馬收到回調。
來看下具體代碼
//LiveData.java
@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
assertMainThread("observeForever");
//1
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper 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;
}
wrapper.activeStateChanged(true);
}
注釋 1 :這里用到的是AlwaysActiveObserver而 observe
方法用到是LifecycleBoundObserver
看一下這個AlwaysActiveObserver
//LiveData.java
private class AlwaysActiveObserver extends ObserverWrapper {
AlwaysActiveObserver(Observer<? super T> observer) {
super(observer);
}
@Override
boolean shouldBeActive() {
return true;
}
}
代碼非常的簡潔,在shouldBeActive
方法中,直接 return true,這也太秀了吧
為啥直接返回 true 呢?因為這里不用管生命周期,永遠都是活躍狀態,所以這個方法叫observeForever
LiveData 的源碼非常值得讀,而且量不是很大,里面有許多值得學習的地方。
9.使用 LiveData 的優勢
這個是Google官方總結的
使用 LiveData 具有以下優勢:
-
確保界面符合數據狀態
LiveData 遵循觀察者模式。當生命周期狀態發生變化時,LiveData 會通知
Observer
對象。您可以整合代碼以在這些Observer
對象中更新界面。觀察者可以在每次發生更改時更新界面,而不是在每次應用數據發生更改時更新界面。 -
不會發生內存泄漏
觀察者會綁定到
Lifecycle
對象,并在其關聯的生命周期遭到銷毀后進行自我清理。 -
不會因 Activity 停止而導致崩潰
如果觀察者的生命周期處于非活躍狀態(如返回棧中的 Activity),則它不會接收任何 LiveData 事件。
-
不再需要手動處理生命周期
界面組件只是觀察相關數據,不會停止或恢復觀察。LiveData 將自動管理所有這些操作,因為它在觀察時可以感知相關的生命周期狀態變化。
-
數據始終保持最新狀態
如果生命周期變為非活躍狀態,它會在再次變為活躍狀態時接收最新的數據。例如,曾經在后臺的 Activity 會在返回前臺后立即接收最新的數據。
-
適當的配置更改
如果由于配置更改(如設備旋轉)而重新創建了 Activity 或 Fragment,它會立即接收最新的可用數據。
-
共享資源
您可以使用單一實例模式擴展
LiveData
對象以封裝系統服務,以便在應用中共享它們。LiveData
對象連接到系統服務一次,然后需要相應資源的任何觀察者只需觀察LiveData
對象。如需了解詳情,請參閱擴展 LiveData。
10.總結
開始回答第 3 節的拋出的問題
10.1.LiveData 是怎么回調的?
- LiveData通過
observe
或者observeForever
方法訂閱了一個觀察者 - LiveData 通過調用
setValue
或postValue
方法時,會取出觀察者,調用它的onChanged
方法 - 當然,當 Activity、Fragment 生命周期由非活躍變化為活躍狀態,也會收到最新的值回調
onChanged
方法,注意這個對應的是LiveData的observe
方法。
10.2.LiveData 為什么可以感知生命周期?
- 是因為LifecycleBoundObserver類
- 以及在
observe
方法中調用了owner.getLifecycle().addObserver(wrapper);
這行代碼,具體的看下上面的源碼分析吧
10.3.LiveData 可以感知生命周期,有什么用,或者說有什么優勢?
- 可以自動取消訂閱
- 防止內存泄漏
10.4.LiveData 為什么只會將更新通知給活躍的觀察者。非活躍觀察者不會收到更改通知?
- 在每次調用
setValue
方法時,最走到LifecycleBoundObserver的shouldBeActive這個方法的判斷上 - 這個方法返回的是狀態為STARTED之后的狀態才會走通知觀察者回調的邏輯,否則就不執行,具體的看下上面的源碼
10.5.LiveData此外還提供了observerForever()方法,所有生命周期事件都能通知到,怎么做到的?
- 看 8.4 小節,有詳細的分析。
- 主要AlwaysActiveObserver的shouldBeActive這個方法直接返回的 true
11.源碼地址
12.原文地址
Android Jetpack組件LiveData基本使用和原理分析
13.參考文章
Android官方架構組件LiveData: 觀察者模式領域二三事
推薦一下我開源的項目 WanAndroid 客戶端
WanAndroidJetpack 架構圖
- 一個純 Android 學習項目,WanAndroid 客戶端。
- 項目采用
MVVM
架構,用Kotlin
語音編寫。 - Android Jetpack 的大量使用包括但不限于
Lifecycle
、LiveData
、ViewModel
、Databinding
、Room
、ConstraintLayout
等,未來可能會更多。 - 采用
Retrofit
和Kotlin-Coroutine
協程進行網絡交互。 - 加載圖片
Glide
主流加載圖片框架。 - 數據存儲主要用到了
Room
和騰訊的MMKV
。
Kotlin + MVVM + Jetpack + Retrofit + Glide 的綜合運用,是學習 MMVM 架構的不錯的項目。
此項目本身也是一個專門學習 Android 相關知識的 APP,歡迎下載體驗!
源碼地址(附帶下載鏈接)
APP 整體概覽
喜歡的點個 Stars,有問題的請提 Issues。