導語
Jetpack簡介及其它組件文章
還在擔心View層的內存泄漏嗎?還在擔心一些空指針異常嗎?LiveData幫你解決這些問題。
主要內容
- LiveData是什么
- LiveData的基本使用
- postValue和setValue有什么區別
- observe是如何收到通知的
- LiveData的粘性事件
- 如何解決LiveData的粘性事件
具體內容
LiveData是什么
- LiveData是一個數據持有類
- 能夠感知組件的生命周期
- 持有的數據可以被觀察者觀察
簡單地來說就是當LiveData持有的數據發生改變的時候,觀察者在生命周期處于STARTED或RESUMED狀態時,LiveData會更新通知給活躍的觀察者。
LiveData的基本使用
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//創建一個LiveData
MutableLiveData<String> mutableLiveData = new MutableLiveData<>();
//注冊觀察者
mutableLiveData.observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
Log.d("LiveData", s);
}
});
//其它線程執行完任務對LiveData進行通知
new Thread(new Runnable() {
@Override
public void run() {
//postValue() 可以在任意線程使用
mutableLiveData.postValue("通知");
//setValue() 只能在主線程被調用
// mutableLiveData.setValue("通知");
}
}).start();
}
}
從上面的代碼可以看出,LiveData的基本使用很簡單,同時我在代碼中注釋講setValue()
只能在主線程被調用,接下來我們深入源碼再看一下。
postValue和setValue有什么區別
我們可以分別點擊postValue和setValue方法,進入它們的源碼進行觀察。
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
/**
* Sets the value. If there are active observers, the value will be dispatched to them.
* <p>
* This method must be called from the main thread. If you need set a value from a background
* thread, you can use {@link #postValue(Object)}
*
* @param value The new value
*/
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
我們可以先看setValue()
,可以看到setValue()
有個注解@MainThread
,方法上面也有注釋This method must be called from the main thread.
,都表明了這個方法只能在主線程被調用。
我們再跟蹤一下postValue方法。postValue方法執行了一行比較重要的代碼:ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
看樣子是交給主線程去執行一個Runnable
。我們進入這個Runnable
看一下。
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
//noinspection unchecked
setValue((T) newValue);
}
};
我們可以看到,Runnable
最終又調用了setValue()
。
看到這里我們就知道了,postValue()
和setValue()
的作用是相同的,區別是postValue()
可以在任意線程調用,setValue()
只能在主線程調用。
因為postValue()
可以在任意線程調用,所以mPendingData
使用了volatile
關鍵字,同時通過synchronized
對代碼塊進行加鎖,來保證線程安全。
可以通過setValue
方法看到,mData
才是我們真正的數據持有者。
observe是如何收到通知的
我們來直接看源碼,我們先看LiveData.observe()
方法。
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
LiveData.LifecycleBoundObserver wrapper = new LiveData.LifecycleBoundObserver(owner, observer);
LiveData.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);
}
其中LifecycleBoundObserver
持有了我們傳入的Observer<? super T> observer
,最后放到了mObservers
這個對象了,這個對象是一個Map
,所以我們可以一對多。
owner.getLifecycle().addObserver(wrapper)
這個代碼不重點講了,這個是Lifecycle
提供的功能,如果不了解可以看我其它文章或者去網上找一下。總之就是把wrapper
和LifecycleOwner
的生命周期進行了綁定。
我們再來看setValue()
方法是如何通知的。
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
void dispatchingValue(@Nullable LiveData.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>, LiveData.ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
private void considerNotify(LiveData.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;
//noinspection unchecked
observer.mObserver.onChanged((T) mData);
}
這段代碼比較長,不要慌,很簡單,有些代碼不重要直接往下看。
直接看dispatchingValue(null)
到底做了啥。首先我們傳入了null
,所以會走else
,我們看到這里使用Iterator
對mObservers
進行遍歷,之前說到mObservers
是一個map
,然后取出值執行considerNotify(iterator.next().getValue())
方法,在considerNotify()
里,最終調用observer.mObserver.onChanged((T) mData)
,把結果回調給我們業務層。
LiveData的粘性事件
我們來看一段代碼,想一下Log會如何輸出。
public class MainActivity extends AppCompatActivity {
MutableLiveData<String> mutableLiveData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mutableLiveData = new MutableLiveData<>();
mutableLiveData.postValue("----------------》通知1");
}
//點擊事件 寫在xml里了
public void observe(View view) {
mutableLiveData.observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
Log.d("LiveData", s);
}
});
mutableLiveData.observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
Log.d("LiveData", s);
}
});
}
}
我們有一個點擊事件,放到了xml里,我們先postValue()
,通過點擊按鈕再注冊observer
,會怎樣呢?
2021-03-10 16:52:07.251 25476-25476/com.example.jetpack D/LiveData: ----------------》通知1
2021-03-10 16:52:07.251 25476-25476/com.example.jetpack D/LiveData: ----------------》通知1
居然也收到了通知,這是為什么呢?我們來通過源碼看一下。
我們在LiveData.observe()
的時候,創建了LifecycleBoundObserver
,LifecycleBoundObserver
繼承ObserverWrapper
,我們直接來看LifecycleBoundObserver
和ObserverWrapper
的代碼。
class LifecycleBoundObserver extends LiveData.ObserverWrapper implements GenericLifecycleObserver {
//...
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
//...
}
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);
}
}
}
LifecycleBoundObserver
最終還繼承了LifecycleEventObserver
,LifecycleEventObserver
有一個方法onStateChanged()
,首先要了解onStateChanged()
方法是Lifecycle
提供的功能,如果不了解可以看我其它文章或者去網上找一下。總之就是在Lifecycle
的生命周期發生改變的時候調用,所以當LiveData.observer()
的時候,就會調用到onStateChanged()
,然后再調用到activeStateChanged()
,最終執行了dispatchingValue(this)
,這句很熟悉呀,就是和setValue()
最終執行的是一樣的代碼塊。不同的是傳入的參數不為空了,所以直接執行considerNotify(initiator)
,不用遍歷了。我們再來看一下這個方法我們還沒有講到的地方。
private void considerNotify(LiveData.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;
//noinspection unchecked
observer.mObserver.onChanged((T) mData);
}
我們一直向下走,直接來到considerNotify
方法,重要的一行代碼是observer.mLastVersion >= mVersion
,分別點擊兩個version
去看一下,就明白了,分別是ObserverWrapper
的版本號和LiveData
的版本號,ObserverWrapper
的版本號大于LiveData
的版本號時,我們就返回,反之則執行,也就是說在什么情況下會執行呢?
舉例我們剛才的事例代碼,當LiveData
創建的時候,mVersion
的版本號為-1
,當LiveData
執行setValue
的時候,執行mVersion++
結果為0
,剛創建ObserverWrapper
的時候,mLastVersion
的版本是-1
,這個時候-1 >= 0
的結果為false
,所以向下執行不會return
,把mVersion
賦值給ObserverWrapper
的mLastVersion
,防止多次被回調,最終執行observer.mObserver.onChanged((T) mData)
。
如何解決LiveData的粘性事件
網上大多數的方案是通過反射,在第一次observer
的時候,修改ObserverWrapper
的mLastVersion
的值。
我的解決方案有點不太一樣,通過代理模式攔截observer
。
我也上傳到github了,可以給俺點幾個小星星,謝謝。
/**
* Created by guoshichao on 2021/3/10
* 非粘性LiveData事件
*/
public class NonStickyLiveData<T> extends MutableLiveData<T> {
static final int START_VERSION = -1;
private int mVersion = START_VERSION;
@Override
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
ObserverProxy observerProxy = new ObserverProxy<>(observer);
observerProxy.preventNextEvent = mVersion > START_VERSION;
super.observe(owner, observerProxy);
}
@Override
public void setValue(T value) {
mVersion++;
super.setValue(value);
}
private class ObserverProxy<T> implements Observer<T> {
@NonNull
private final Observer<T> observer;
private boolean preventNextEvent = false;
ObserverProxy(@NonNull Observer<T> observer) {
this.observer = observer;
}
@Override
public void onChanged(@Nullable T t) {
if (preventNextEvent) {
preventNextEvent = false;
return;
}
observer.onChanged(t);
}
}
}
如果這樣寫有問題或者會出現bug,歡迎大家聯系我。