前言
在了解LiveData并學習其原理之前,需要先知道Lifecycle的使用以及原理,否則下文某些部分可能較難理解。
約定
Observer : 下文無特殊說明都稱為觀察者
LifecycleOwner: 下文無物特殊說明均稱owner(被觀察者——具有生命周期)
LiveData是什么
引用源碼對于LiveData的注釋,個人感覺解釋得很到位
/**
* LiveData is a data holder class that can be observed within a given lifecycle.
* This means that an {@link Observer} can be added in a pair with a {@link LifecycleOwner}, and
* this observer will be notified about modifications of the wrapped data only if the paired
* LifecycleOwner is in active state. LifecycleOwner is considered as active, if its state is
*/
語意大致如下:
LiveData所持有數據可被感知。在LiveData里,觀察者與owner成對出現(當然有例外,后面再說)。在LiveData所持有包裝過的數據有變化時,觀察者處于active狀態時回得到通知。
owner狀態處于State.STARTED或State.RESUME時觀察者被認為是active狀態。
簡單來說,LiveData作為一種媒介去持有數據,在數據發生改變時,去通知監測owner并處于active狀態的觀察者作出應對。
案例
public class MyData extends LiveData<String> {
private static final String TAG = "T-MyData";
public MyData(){
setValue("hi");
}
@Override
protected void onActive() {
super.onActive();
Log.d(TAG, "onActive ");
}
@Override
protected void onInactive() {
super.onInactive();
Log.d(TAG, "onInactive ");
}
public void changeValue(String value){
setValue(value);
}
}
public class MainActivity extends AppCompatActivity {
private static final String TAG = "T-MainActivity";
MyData data = new MyData();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.text).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
data.changeValue(data.getValue() + "~");
}
});
data.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String value) {
Log.d(TAG, "onChanged: " + value );
}
});
}
}
案例行為:LiveData持有String數據,并在MainActivity(也就是owner)生命周期內,觀察者對觀察其數據。String初始為“hi”,每點擊頁面上的按鈕String在原有拼接上“~”。在數據改變時,onChanged()可接受到改變的數據。 在點擊三次案后讓MainActiviy進入不可見狀態
日志如下
從日志上看數據已被感知,此外觸發了onActive()以及onInactive() , 二者在什么時候會被觸發,下文會有說明。
原理
重要函數
對于使用LiveData重要且包含需要注意事項,挑出以預警
- setValue()
protected void setValue(T value) {
assertMainThread("setValue");
.....
}
此函數設置LiveData里的數據,并且執行在主線程里
- postValue()
protected void postValue(T value) {
.....
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
與setValue功能相同,可執行在非主線程
-getValue() : 獲取LiveData里的數據,但不保證一定接收到最新數據(比如在異步線程里更新數據被耽誤了)
注冊過程
前文所述,onwer與觀察者稱對出現。可通過observe注冊。此外,也可通過observeForever進行注冊,與observer會有差異。此處針對observe方式先做闡述,observeForver在后文再做比對。
- LiveData.obsever()
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
// owner處于Destroy狀態已無注冊必要
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
// 將owner與觀察者進行綁定
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
// 一個觀察者僅僅針對一個onwer
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
// 這里的getLifecycle一般是Lifecycle里說的LifecycleRegistry
owner.getLifecycle().addObserver(wrapper);
}
從代碼上看,注冊時,先排查owner狀態是否合適,緊接著將owner與觀察者進行了綁定,且從拋出的異常可以知道,owner與觀察者的關系為一對多。此后將包裝好的ObserverWrapper交給LifecycleRegistry,這樣,就確保了再State.Event事件到達時,ObserverWrapper會接受到訊息。 (Lifecycle知識,忘了去這里->傳送門)
綁定過程
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
@NonNull final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) {
super(observer);
mOwner = owner;
}
.....
}
private abstract class ObserverWrapper {
final Observer<T> mObserver;
ObserverWrapper(Observer<T> observer) {
mObserver = observer;
}
......
}
這里貼出了LifecycleBoundObserver與其父類ObserverWrapper的部分內容,可見兩者分別持有了owner與觀察者信息。
到這里,整個注冊過程完畢。過程很簡單,做個小結
- 綁定owner與觀察者,信息收集入LifecycleBoundObserver
- 將LifecycleBoundObserver交接給LifecycleRegistry進行注冊,以便Event事件到來時得以接收
感知過程
在Lifecycle知識里知道,Event最終會經過GenericLifecycleObserver的實現類作為中轉者經過處理,傳達到具體的觀察者。從之前的代碼截圖可以知道LifecycleBoundObserver是GenericLifecycleObserver的實現類,因此能接收到Event事件。
public interface GenericLifecycleObserver extends LifecycleObserver {
void onStateChanged(LifecycleOwner source, Lifecycle.Event event);
}
GenericLifecycleObserver對于Lifecycle的體系來說,是個觀察者(針對Lifecycle),與實際的觀察者(針對Lifecycle),兩種是職責上的區別,因此,職責是可以同時抗在肩上的。
回顧一下Lifecycle的原理,代碼位置如下
當前位置
- LifecycleRegistry.addObserver()
-- ObserverWithState()
--- Lifecycling.getCallback()
static GenericLifecycleObserver getCallback(Object object) {
.....
if (object instanceof GenericLifecycleObserver) {
return (GenericLifecycleObserver) object;
}
.....
}
可見,如果觀察者(針對Lifecycle)是GenericLifecycleObserver的話,Event事件是由觀察者(針對Lifecycle)自行處理的,此類觀察者包攬了以上所述職責。(可以查看Lifecycle體系里的SingleGeneratedAdapterObserver會一目了然,如果都忘了傳送門,對于理解很重要)。
當前位置
- LifecycleBoundObserver.onStateChanged()
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
// 檢查owner狀態
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
// 已銷毀移除,避免內存泄漏
removeObserver(mObserver);
return;
}
// 檢測觀察者是否處于active狀態,并作出相應對策
activeStateChanged(shouldBeActive());
}
}
當前位置
- LifecycleBoundObserver. shouldBeActive()
@Override
boolean shouldBeActive() {
// true標示owner至少處于State.STARTED狀態
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
不解釋
當前位置
- LifecycleBoundObserver. activeStateChanged()
void activeStateChanged(boolean newActive) {
// 同一狀態下不做處理
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
// 更新狀態
mActive = newActive;
// 是否有處于active狀態的觀察者
boolean wasInactive = LiveData.this.mActiveCount == 0;
LiveData.this.mActiveCount += mActive ? 1 : -1;
1??
if (wasInactive && mActive) {
onActive();
}
2??
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive();
}
// 通知數據情況
if (mActive) {
dispatchingValue(this);
}
}
1和2標注部分是指,owner處于State.STARTED、State.RESUMED時觀察者為active狀態,而State.INITIALIZED、State.CREATED為inActive狀態,因此,同種狀態下僅做單次回調。
數據通知
當前位置
LifecycleBoundObserver. dispatchingValue()
private 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<T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
// 嘗試通知觀察者
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
這里僅需知道dispatchingValue()會根據觀察者的不同,都會嘗試通知觀察者。
當前位置
- LifecycleBoundObserver. dispatchingValue()
-- considerNotify()
private void considerNotify(ObserverWrapper observer) {
// 觀察者處于inActive狀態
if (!observer.mActive) {
return;
}
// 源碼注釋為,檢查觀察者是否響應此次更改的意義在于,雖然觀察者可能
// 處于響應的狀態,但此時并沒有接收到明確的Event通知,最好不要通知以
// 保持良好的通知秩序
// 這里可以理解為,防止素亂而引起的可能的內存泄漏的問題,也為了保證
// 同一狀態下僅做單次通知
if (!observer.shouldBeActive()) {
// 這里回到了觸發considerNotify的起點,是為了等待,修復素亂
observer.activeStateChanged(false);
return;
}
// 數據沒有更改不做通知
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
// 觀察者回調
observer.mObserver.onChanged((T) mData);
}
除了代碼中注釋處的解釋,還要知道的信息是,LiveData擁有私有變量mVersion對持有數據版本做了維護,只有檢測到版本更新時才做通知。
此外,在setValue()是也能觸發considerNotify()
protected void setValue(T value) {
// 在主線程執行
assertMainThread("setValue");
// 數據版本更新
mVersion++;
mData = value;
// 通知
dispatchingValue(null);
}
分發過程結束,小結如下:
- ObserverWrapper與子類負責持有owner與觀察者信息,并實現GenericLifecycleObserver自行處理Event事件
- Event事件到達時,根據owner的State做LiveData做相應處理,在觀察者處于active狀態時,回調onActive(); 在處于inActive時回調onInactive()
- owner生命周期轉變時或更新數據時,LiveData向處于active狀態的觀察者進行通知
提醒
文章到這里還沒有結束,對于LiveData而言,注冊防止不僅提供了observe的注冊方式,還提供了observeForever的注冊方式
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer)
public void observeForever(@NonNull Observer<T> observer)
僅從參數上來看,很容易想到觀察者并沒有針對指定的onwer進行綁定,從之前的分析來看,在onwer銷毀時,觀察者也會一并被銷毀,因此,此處能聯想到,較之Observe的注冊方式,observeForever會注冊的觀察者自身會擁有更廣闊的生命周期。
- Adds the given observer to the observers list. This call is similar to * {@link LiveData#observe(LifecycleOwner, Observer)} with a LifecycleOwner, which is always active. This means that the given observer will receive all events and will never be automatically removed. You should manually call {@link#removeObserver(Observer)} to stop observing this LiveData.
摘自源碼對于observeForever的注釋,大意如下:
此方法與observe相似,但是觀察者總會收到事件并且不會被自動移除,需要手動移除。
可見,在使用上以及原理處需要做甄別。
案例
public class MainActivity extends AppCompatActivity {
private static final String TAG = "T-MainActivity";
MyData data = BActivity.data;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.text).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
data.changeValue(data.getValue() + "~");
}
});
findViewById(R.id.startBtn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, BActivity.class);
startActivity(intent);
}
});
}
}
public class BActivity extends AppCompatActivity {
private static final String TAG = "T-BActivity";
public static MyData data = new MyData();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);
data.observeForever(new Observer<String>() {
@Override
public void onChanged(@Nullable String value) {
Log.d(TAG, "I'am still here , value is : " + value);
}
});
}
@Override
public void onBackPressed() {
super.onBackPressed();
finish();
}
}
頁面描述:在B頁面有LiveData的靜態對象,在按下返回鍵時B會被銷毀。Main頁面有Click Me按鈕,點擊時LiveData的數據加上"~"拼接,并有另一個按鈕以啟動B頁面。
頁面操作:從Main啟動B,按下返回鍵,多次點擊Click Me按鈕,日志如下
容易證實,觀察者依舊存在。
observeForever原理
public void observeForever(@NonNull Observer<T> observer) {
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
// 除了和observe()類似的檢測外,還不能是LifecycleBoundObserver類
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);
}
代碼上看,流程是類似的,不過observeForever()并不能使用observe()使用的LifecycleBoundObserver,并且沒有通過Lifecycle.LifecycleRegistry進行注冊,能猜測通過此方式注冊的觀察者,并沒有和實際的owner進行綁定(之前所說的沒有成對出現的情況)。答案會在AlwaysActiveObserver里找到
private class AlwaysActiveObserver extends ObserverWrapper {
AlwaysActiveObserver(Observer<T> observer) {
super(observer);
}
@Override
boolean shouldBeActive() {
return true;
}
}
AlwaysActiveObserver很簡單,僅有shouldBeActive()方法 ,并且結合之前所述的通過Observe()注冊,能知道通過observeForever()注冊的觀察者性質如下:
- 并沒有利用Lifycycle的機制,所以沒有對生命周期的感知
- 行為就是簡單的觀察者模式的簡單監聽與回調
- 有內存泄漏風險,記得手動移除
簡單原理圖
圖片除了注冊過程以及感知過程外,還畫出了接收過程,因為理解Lifecycle原理真的對理解很重要
提示
文章到這里就結束了,以下部分為小插曲,感興趣歡迎閱讀
插曲
LiveData的優勢在于讓數據感知生命周期的變化以及實現數據的共享。在學習LiveData的過程中,有查閱過一些相應的博文,其中讓我很關注的地方是,有些地方指出,使用單例讓LiveData實現數據共享,并對此不再做必要的解釋,很容易引起混淆和誤解。
單例只是無可奈何之下的一種形式,是最差解。
LiveData的數據共享的精髓在于利用觀察者,而不是利用過長的生命周期。并且,LiveData所要解決的問題是,具有生命周期的組件如何在自身的生命周期里根據必要性的或者重要性的數據狀態,來調整自身的狀態,并實現生命周期監測與數據狀態的解耦。
筆者的呢喃:我都單例了,我都自我共享了,我還需要感知 0 0?
(筆者在??中使用了靜態對象LiveData僅僅是為了方便展示,實際運用中不要這么干)
在此感謝涂哥的指導和答疑
下一篇:ViewModel