前言
本篇文章主要講解LiveData工作的原理,如果還不知道LiveData如何用的話,請參考官方文件。 LiveData的講解涉及到了Lifecycle的知識,如果你還不瞭解LifeCycle,請參考文件LifeCycle介紹。
介紹
LiveData是一個資料持有類,它可以通過新增觀察者被其他元件觀察其變更。不同於普通的觀察者,它最重要的特性就是遵從應用程式的生命週期,如在Activity中如果資料更新了但Activity已經是destroy狀態,LivaeData就不會通知Activity(observer)。當然。LiveData的優點還有很多,如不會造成記憶體洩漏等。
LiveData通常會配合ViewModel來使用,ViewModel負責觸發資料的更新,更新會通知到LiveData,然後LiveData再通知活躍狀態的觀察者。
原理分析
下面直接看程式碼:
public class UserProfileViewModel extends ViewModel {
private String userId;
private MutableLiveData<User> user;
private UserRepository userRepo;
public void init(String userId) {
this.userId = userId;
userRepo = new UserRepository();
user = userRepo.getUser(userId);
}
public void refresh(String userId) {
user = userRepo.getUser(userId);
}
public MutableLiveData<User> getUser() {
return user;
}
}
複製程式碼
上面UserProfileViewModel內部持有 UserRepository 中 MutableLiveData的引用,並且提供了獲取 MutableLiveData 的方法 getUser(),UserRepository 負責從網路或資料庫中獲取資料並封裝成 MutableLiveData 然後提供給 ViewModel。
我們在 UserProfileFragment 中為 MutableLiveData 註冊觀察者,如下:
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
String userId = getArguments().getString(UID_KEY);
viewModel = ViewModelProviders.of(this).get(UserProfileViewModel.class);
viewModel.init(userId);
//標註1
viewModel.getUser().observe(UserProfileFragment.this, new Observer<User>() {
@Override
public void onChanged(@Nullable User user) {
if (user != null) {
tvUser.setText(user.toString());
}
}
});
}
複製程式碼
看標註1處,viewModel.getUser()獲取到 MutableLiveData 也就是我們的 LiveData,然後呼叫 LiveData的observer方法,並把UserProfileFragment作為引數傳遞進去。observer() 方法就是我們分析的入口了,接下來我們看LiveData的observer()方法都做了什麼:
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
//標註1
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
//標註2
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);
}
複製程式碼
可以看到,UserProfileFragment 是作為 LifeCycleOwner 引數傳進來的,如果你的support包版本大於等於26.1.0,support包中的 Fragment 會預設繼承自 LifecycleOwner,而 LifecycleOwner 可獲取到該元件的 LifeCycle,也就知道了 UserProfileFragment 元件的生命週期(在這裡預設大家已經瞭解過LifeCycle了)。
看標註1處,如果我們的 UserProfileFragment 元件已經是destroy狀態的話,將直接返回,不會被加入觀察者行列。如果不是destroy狀態,就到標註2處,新建一個 LifecycleBoundObserver 將我們的 LifecycleOwner 和 observer儲存起來,然後呼叫 mObservers.putIfAbsent(observer, wrapper) 將observer和wrapper分別作為key和value存入Map中,putIfAbsent()方法會判斷如果 value 已經能夠存在,就返回,否則返回null。
如果返回existing為null,說明以前沒有新增過這個觀察者,就將 LifecycleBoundObserver 作為 owner 生命週期的觀察者,也就是作為 UserProfileFragment 生命週期的觀察者。
我們看下LifecycleBoundObserver 原始碼:
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
@NonNull final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<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);
}
}
複製程式碼
程式碼並不多,LifecycleBoundObserver 繼承自 ObserverWrapper 並實現了 GenericLifecycleObserver介面,而 GenericLifecycleObserver 介面又繼承自 LifecycleObserver 介面,那麼根據 Lifecycle 的特性,實現了LifecycleObserver介面並且加入 LifecycleOwner 的觀察者裡就可以感知或主動獲取 LifecycleOwner 的狀態。
好了,看完了觀察者,那麼我們的LiveData什麼時候會通知觀察者呢?不用想,肯定是資料更新的時候,而資料的更新是我們程式碼自己控制的,如請求網路返回User資訊後,我們會主動將User放入MutableLiveData中,這裡我在UserRepository中直接模擬網路請求如下:
public class UserRepository {
final MutableLiveData<User> data = new MutableLiveData<>();
public MutableLiveData<User> getUser(final String userId) {
if ("xiasm".equals(userId)) {
data.setValue(new User(userId, "夏勝明"));
} else if ("123456".equals(userId)) {
data.setValue(new User(userId, "哈哈哈"));
} else {
data.setValue(new User(userId, "unknow"));
}
return data;
}
}
複製程式碼
當呼叫getUser()方法的時候,我們呼叫MutableLiveData的setValue()方法將資料放入LiveData中,這裡MutableLiveData實際上就是繼承自LiveData,沒有什麼特別:
public class MutableLiveData<T> extends LiveData<T> {
@Override
public void postValue(T value) {
super.postValue(value);
}
@Override
public void setValue(T value) {
super.setValue(value);
}
}
複製程式碼
setValue()在放入User的時候必須在主執行緒,否則會報錯,而postValue則沒有這個檢查,而是會把資料傳入到主執行緒。我們直接看setValue()方法:
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
複製程式碼
首先呼叫assertMainThread()檢查是否在主執行緒,接著將要更新的資料賦給mData,然後呼叫 dispatchingValue()方法並傳入null,將資料分發給各個觀察者,如我們的 UserProfileFragment。看 dispatchingValue()方法實現:
private void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
//標註1
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
//標註2
for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
複製程式碼
從標註1可以看出,dispatchingValue()引數傳null和不傳null的區別就是如果傳null將會通知所有的觀察者,反之僅僅通知傳入的觀察者。我們直接看標註2,通知所有的觀察者通過遍歷 mObservers ,將所有的 ObserverWrapper 拿到,實際上就是我們上面提到的 LifecycleBoundObserver,通知觀察者呼叫considerNotify()方法,這個方法就是通知的具體實現了。
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;
//noinspection unchecked
observer.mObserver.onChanged((T) mData);
}
複製程式碼
如果觀察者不是活躍狀態,將不會通知此觀察者,看最後一行,observer.mObserver.onChanged((T) mData),observer.mObserver就是我們呼叫LiveData的observer()方法傳入的 Observer,然後呼叫 Observer 的 onChanged((T) mData)方法,將儲存的資料mData傳入,也就實現了更新。在看下我們實現的Observer:
viewModel.getUser().observe(UserProfileFragment.this, new Observer<User>() {
@Override
public void onChanged(@Nullable User user) {
if (user != null) {
tvUser.setText(user.toString());
}
}
});
複製程式碼
如果哪個控制元件要根據user的變更而及時更新,就在onChanged()方法裡處理就可以了。到這裡,LiveData已經能夠分析完了,其實LiveData的實現還是要依賴於Lifecycle。