Q:什么是LiveData?
LiveData是一種可觀察的數(shù)據(jù)存儲器類。與常規(guī)的可觀察類不同,LiveData 具有生命周期感知能力,意指它遵循其他應(yīng)用組件(如 Activity、Fragment 或 Service)的生命周期。這種感知能力可確保 LiveData 僅更新處于活躍生命周期狀態(tài)的應(yīng)用組件觀察者。
Q:請談?wù)凩iveData的好處
1.確保界面符合數(shù)據(jù)狀態(tài)
LiveData 遵循觀察者模式。當(dāng)?shù)讓訑?shù)據(jù)發(fā)生變化時,LiveData 會通知Observer對象。您可以整合代碼以在這些Observer對象中更新界面。這樣一來,您無需在每次應(yīng)用數(shù)據(jù)發(fā)生變化時更新界面,因為觀察者會替您完成更新。
2.不會發(fā)生內(nèi)存泄露
觀察者會綁定到Lifecycle對象,并在其關(guān)聯(lián)的生命周期遭到銷毀后進行自我清理。
3.不會因 Activity 停止而導(dǎo)致崩潰
如果觀察者的生命周期處于非活躍狀態(tài)(如返回棧中的 Activity),則它不會接收任何 LiveData 事件。
4.不再需要手動處理生命周期
界面組件只是觀察相關(guān)數(shù)據(jù),不會停止或恢復(fù)觀察。LiveData 將自動管理所有這些操作,因為它在觀察時可以感知相關(guān)的生命周期狀態(tài)變化。
5.數(shù)據(jù)始終保持最新狀態(tài)
如果生命周期變?yōu)榉腔钴S狀態(tài),它會在再次變?yōu)榛钴S狀態(tài)時接收最新的數(shù)據(jù)。例如,曾經(jīng)在后臺的 Activity 會在返回前臺后立即接收最新的數(shù)據(jù)。
6.適當(dāng)?shù)呐渲酶?/strong>
如果由于配置更改(如設(shè)備旋轉(zhuǎn))而重新創(chuàng)建了 Activity 或 Fragment,它會立即接收最新的可用數(shù)據(jù)。
7.共享資源
您可以使用單例模式擴展LiveData對象以封裝系統(tǒng)服務(wù),以便在應(yīng)用中共享它們。LiveData對象連接到系統(tǒng)服務(wù)一次,然后需要相應(yīng)資源的任何觀察者只需觀察LiveData對象。
Q:LiveData為什么可以自動取消訂閱,如何避免內(nèi)存泄漏?
調(diào)用 observe 方法時,會調(diào)用 owner.getLifecycle().addObserver 以達到感知生命周期的目的。
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
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);
}
其中的觀察者是owner和observer的包裝對象LifecycleBoundObserver
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);
}
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
當(dāng)Lifecycles的State發(fā)生變化會回調(diào)onStateChanged方法,當(dāng)State為DESTROYED時,則移除觀察者Observer。里面調(diào)用的是LiveData的removeObserver方法。
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);
}
當(dāng)頁面銷毀時,在mObservers中remove了observer,就這樣完成了訂閱的自動取消。
Q:LiveData傳相同的值會不會執(zhí)行onchanged回調(diào)?
給LiveData傳值有兩種方式
setValue()和postValue(),它們之間的區(qū)別在于前者只能在主線程使用,后者可以在任意線程中調(diào)用,傳入的數(shù)據(jù)會暫存為mPendingData,最終會使用Handler切換回主線程中調(diào)用setValue(mPendingData)進行數(shù)據(jù)更新。
注意的是,postValue()被多次調(diào)用時,暫存數(shù)據(jù)mPendingData會被postValue()傳入的數(shù)據(jù)覆蓋,最終數(shù)據(jù)為最后一次的數(shù)據(jù)。而postValue()發(fā)起的主線程任務(wù),在執(zhí)行到之前,只會存在一個任務(wù)。
查看setValue方法:
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
注意mVersion的值,查看dispatchingValue方法:
void dispatchingValue(@Nullable ObserverWrapper initiator) {
....
considerNotify(initiator);
....
}
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;
observer.mObserver.onChanged((T) mData);
}
只要mVersion是大于等于之前的值,就會回調(diào)onChanged方法,也就是說,不管值是否相同,只看version的值。
Q:談?wù)勀銓bserveForever的認識?
// LiveData.java
@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
assertMainThread("observeForever");
// 創(chuàng)建AlwaysActiveObserver
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing instanceof LiveData.LifecycleBoundObserver) {
// 如果existing是LiveData.LifecycleBoundObserver類的實例,拋出異常
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
// 調(diào)用AlwaysActiveObserver的activeStateChanged方法,并且傳入true
wrapper.activeStateChanged(true);
}
再看下AlwaysActiveObserver的代碼:
// LiveData.java
private class AlwaysActiveObserver extends ObserverWrapper {
AlwaysActiveObserver(Observer<? super T> observer) {
super(observer);
}
// 重寫了shouldBeActive方法,并且返回true,根據(jù)上面的代碼分析可知,這個方法是用來判斷是否為活躍狀態(tài),這里一直返回true,也就是說一直保持著活躍狀態(tài)
@Override
boolean shouldBeActive() {
return true;
}
}
observeForever是用于將指定的觀察者添加到觀察列表中,類似于調(diào)用observer方法,但是給定的LifecycleOwner狀態(tài)總是為活躍狀態(tài),這意味著觀察者將永遠接收所有的事件,所以如果要停止觀察這個LiveData,就要手動調(diào)用removeObserver方法。
Q:PostValue收不到數(shù)據(jù)變更的通知的問題是否遇到過?或者說使用PostValue需要注意的問題
當(dāng)連續(xù)調(diào)用 postValue 時,有可能只會收到最后一次數(shù)據(jù)更新通知。
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
mPendingData 被成功賦值 value 后,post 了一個 Runnable
mPostValueRunnable 的實現(xiàn)如下:
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
- postValue 將數(shù)據(jù)存入 mPendingData,mPostValueRunnable 在UI線程消費mPendingData。
- 在 Runnable 中 mPendingData 值還沒有被消費之前,即使連續(xù) postValue , 也不會 post 新的 Runnable
- mPendingData 的生產(chǎn) (賦值) 和消費(賦 NOT_SET) 需要加鎖
簡單的說是因為:
postValue 只是把傳進來的數(shù)據(jù)先存到 mPendingData,然后往主線程拋一個 Runnable,在這個 Runnable 里面再調(diào)用 setValue 來把存起來的值真正設(shè)置上去,并回調(diào)觀察者們。而如果在這個 Runnable 執(zhí)行前多次 postValue,其實只是改變暫存的值 mPendingData,并不會再次拋另一個 Runnable。這就會出現(xiàn)后設(shè)置的值把前面的值覆蓋掉的問題,會導(dǎo)致事件丟失。
Q:為什么PostValue要設(shè)計為只post一次Runnable?
即使 post 多次也沒有意義,所以只 post 一次即可。
對于 setValue 來說,連續(xù)調(diào)用多次,數(shù)據(jù)會依次更新:
如下,訂閱方一次收到 a b 的通知:
liveData.setValue("a");
liveData.setValue("b");
通過源碼可知,dispatchingValue()中同步調(diào)用 Observer#onChanged(),依次通知訂閱方:
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
但對于 postValue,如果當(dāng) value 變化時,我們立即post,而不進行阻塞
protected void postValue(T value) {
mPendingData = value;
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
public void run() {
setValue((T) mPendingData);
}
};
由于線程切換的開銷,連續(xù)調(diào)用 postValue,收到通知只能是b、b,無法收到a。
因此,post 多次已無意義,一次即可。
Q: 為什么要加讀寫鎖?
是否 post 取決于對 mPendingData 的判斷(是否為 NOT_SET)。因為要在多線程環(huán)境中訪問 mPendingData ,不加讀寫鎖無法保證其線程安全。
protected void postValue(T value) {
boolean postTask = mPendingData == NOT_SET; // --1
mPendingData = value; // --2
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
public void run() {
Object newValue = mPendingData;
mPendingData = NOT_SET; // --3
setValue((T) newValue);
}
};
如上,如果在 1 和 2 之間,執(zhí)行了 3,則 2 中設(shè)置的值將無法得到更新。
Q:如何解決或防止LiveData或者MutableLiveData多次回調(diào)的問題
利用SingleLiveEvent 使 observe#LiveData時只相應(yīng)一次onChanged操作
public class SingleLiveEvent<T> extends MutableLiveData<T> {
private static final String TAG = "SingleLiveEvent";
private final AtomicBoolean mPending = new AtomicBoolean(false);
@MainThread
public void observe(LifecycleOwner owner, final Observer<T> observer) {
if (hasActiveObservers()) {
Log.w(TAG, "Multiple observers registered but only one will be notified of changes.");
}
// Observe the internal MutableLiveData
super.observe(owner, new Observer<T>() {
@Override
public void onChanged(@Nullable T t) {
if (mPending.compareAndSet(true, false)) {
observer.onChanged(t);
}
}
});
}
@MainThread
public void setValue(@Nullable T t) {
mPending.set(true);
super.setValue(t);
}
/**
* Used for cases where T is Void, to make calls cleaner.
*/
@MainThread
public void call() {
setValue(null);
}
}
1.SingleLiveEvent 利用 AtomicBoolean (默認為false)進行賦值,當(dāng)LiveData 進行 setValue時改變 AtomicBoolean的值(set(true)
2 使用 AtomicBoolean.compareAndSet(true,false)方法,先進行判斷(此時的AtomicBoolean的值為true)與 compareAndSet設(shè)置的except值(第一個參數(shù))比較,因為相等所以將第二個參數(shù)設(shè)置為AtomicBoolean值設(shè)為false函數(shù)并返回 true
- 當(dāng)再次進入該頁面雖然 LiveData值并沒有改變,仍然觸發(fā)了 observer方法,由于 AtomicBoolean已經(jīng)為 false ,但是 except值為 true,與if 進行判斷所以 并不會繼續(xù)觸發(fā) onChanged(T)方法
即只有在 setValue時相應(yīng)一次onChanged(T)方法。
Android消息總線的演進之路:用LiveDataBus替代RxBus、EventBus
ViewModel的左膀右臂 數(shù)據(jù)驅(qū)動真的香
ViewModel之外的LiveData-使用Transformations和MediatorLiveData的反應(yīng)模式
Android面試:說一下 LiveData 的 postValue ?與SetValue有什么區(qū)別?連續(xù)調(diào)用會有什么問題?為什么?