一、 LiveData簡介
LiveData是Jetpack架構元件Lifecycle 庫的一部分,是一個可感覺生命周期的可觀察容器類 (Observable)。與正常的可觀察類不同,LiveData 具有生命周期感覺能力,這意味着它具有感覺應用元件(如 Activity、Fragment 或 Service)的生命周期的能力,并且LiveData僅更新處于活躍生命周期狀态的應用元件觀察者。
是以,LiveData具有如下一些特效。
- LiveData是一個持有資料的容器類,它持有的資料是可以被觀察者訂閱的,當資料發生變化時會通知觀察者,觀察者可以是 Activity、Fragment、Service 等對象。
- LiveData 具有感覺觀察者的生命周期能力,并且隻有當觀察者處于激活狀态(STARTED、RESUMED)才會接收到資料更新的通知,在未激活時會自動解除注冊觀察者,以降低記憶體洩漏的風險。
- 使用 LiveData 儲存資料時,由于資料群組件是分離的,是以當元件被銷毀時可以保證資料不會丢失。
是以,我們認為LiveData就是一個資料容器,它負責将資料包裹起來,使資料成為被觀察者,當資料發生變化時,LiveData會通知觀察者以便觀察者做出響應。
那相比其他的一些觀察者技術,如RxJava什麼的,LiveData有哪些優勢嗎,下面是官方給出的一些優點列舉。
- 確定 UI 界面始終和資料狀态保持一緻。
- 不會發生記憶體洩漏。觀察者綁定到 Lifecycle 對象并在其相關生命周期 destroyed 後自行解除綁定。
- 不會因為 Activity 停止而發生奔潰。如 Activity執行finish方法後,它就不會收到任何LiveData 事件。
- 不再需要手動處理生命周期。UI 元件隻需觀察相關資料,不需要停止或恢複觀察,LiveData 會自動管理這些操作,因為 LiveData 可以感覺生命周期狀态的更改。
- 資料始終保持最新狀态。在生命周期從非激活狀态變為激活狀态,始終保持最新資料,如背景 Activity 在傳回到前台後可以立即收到資料的最新狀态。
- 适當的配置更改。當配置發生更改(如螢幕旋轉)而重建 Activity / Fragment,它會立即收到最新的可用資料。
- 資源共享。LiveData 很适合用于元件(Activity / Fragment)之間的通信,以及共享資料資源。
二、 LiveData與ViewModel的關系
在Jetpack架構中,ViewModel的主要作用是存儲各種資料,當然,我們也可以在ViewModel中處理一些資料邏輯。例如,我們可以在ViewModel中對加載的資料進行某些加工操作。
而對頁面來說,它并不需要關心ViewModel中的資料邏輯,它隻關心需要展示的資料是什麼,并且在資料發生變化時通知頁面資料的變化并做出相應的更新。而LiveData的作用就是包裝ViewModel中資料,并讓被觀察者能夠觀察資料的變化。下圖是官方Jetpack架構的示意圖。
在這裡插入圖檔描述
三、 LiveData的基本使用
3.1 使用步驟
LiveData的使用比較簡單,主要會涉及以下幾個步驟:
- 建立 LiveData 執行個體以存儲某種類型的資料,通常在ViewModel中完成。
- 定義一個具有onChanged()方法的Observer對象,當LiveData持有資料發生變化時回調該方法。通常,我們可以在UI控制器類中建立該Observer對象,如Activity或Fragment。
- 通過使用observe()方法将上述的LiveData對象和Observer對象關聯在一起。這樣Observer對象就與LiveData産生了訂閱關系,當LiveData資料發生變化時通知,而在Observer更新資料,是以Observer通常是Activity和Fragment。
從上述步驟可以看出,LiveData使用了觀察者模式,觀察者通常是UI控制器,如Activity或Fragment,而被觀察者則是LiveData包谷的資料對象, 當LiveData對象持有資料發生變化,會通知對它訂閱的所有處于活躍狀态的訂閱者。
3.2 LiveData使用示例
3.2.1 建立 LiveData 對象
LiveData是一種可用于任何資料的封裝容器,其中包括可實作 Collections 的對象,如 List。LiveData 對象通常存儲在 ViewModel 對象中,并可通過 getter 方法進行通路,如下所示。
public class NameViewModel extends ViewModel {
private MutableLiveData<String> name;
public MutableLiveData<String> getName() {
if (name == null) {
name = new MutableLiveData<String>();
}
return name;
}
}
複制
3.2.2 觀察 LiveData 對象
在大多數情況下,我們可以應用元件的 onCreate() 方法中開始觀察 LiveData 對象。并且,LiveData 僅在資料發生更改時才發送更新,并且僅發送給活躍觀察者,如下所示。
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private NameViewModel model;
private TextView nameTV;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
nameTV=findViewById(R.id.nameTV);
model = new ViewModelProvider(this).get(NameViewModel.class);
final Observer<String> nameObserver = new Observer<String>() {
@Override
public void onChanged(@Nullable final String newName) {
nameTV.setText(newName);
}
};
model.getName().observe(this, nameObserver);
}
}
複制
當我們傳遞 nameObserver 參數的情況下調用 observe() 後,系統會立即調用 onChanged(),進而提供 mCurrentName 中存儲的最新值,如果 LiveData 對象尚未在 mCurrentName 中設定值,則不會調用 onChanged()。事實上,最簡單的LiveData使用方法是MutableLiveData,如下所示。
public class MainActivity extends AppCompatActivity {
private static final String TAG="MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MutableLiveData<String> mutableLiveData = new MutableLiveData<>();
mutableLiveData.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable final String s) {
Log.d(TAG, "onChanged:"+s);
}
});
mutableLiveData.postValue("Android應用開發實戰");
}
}
複制
3.2.3 更新 LiveData 對象
LiveData 本身沒有公開可用的方法來更新存儲的資料,如果需要修改LiveData的資料,可以使用MutableLiveData 類将公開 setValue(T) 和 postValue(T) 方法。通常情況下會在 ViewModel 中使用 MutableLiveData,然後 ViewModel 隻會向觀察者公開不可變的 LiveData 對象,如下所示。
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String anotherName = "John Doe";
model.getCurrentName().setValue(anotherName);
}
});
複制
3.2.4 擴充 LiveData
如果觀察者的生命周期處于 STARTED 或 RESUMED 狀态,則 LiveData 會認為該觀察者處于活躍狀态。以下示例代碼說明了如何擴充 LiveData 類。
public class StockLiveData extends LiveData<BigDecimal> {
private StockManager stockManager;
private SimplePriceListener listener = new SimplePriceListener() {
@Override
public void onPriceChanged(BigDecimal price) {
setValue(price);
}
};
public StockLiveData(String symbol) {
stockManager = new StockManager(symbol);
}
@Override
protected void onActive() {
stockManager.requestPriceUpdates(listener);
}
@Override
protected void onInactive() {
stockManager.removeUpdates(listener);
}
}
複制
在上面的示例中,我們首先建立一個StockLiveData并繼承自LiveData,并重寫了onActive和onInactive兩個重要方法。
- onActivite():當有活躍狀态的訂閱者訂閱LiveData時會回調該方法,意味着需要在這裡監聽資料的變化。
- onInactive():當沒有活躍狀态的訂閱者訂閱LiveData時會回調該方法,此時沒有必要保持StockManage服務象的連接配接。
- setValue():注意到value=price這裡是調用了setValue(price)方法,通過該方法更新LiveData的值,進而通知處于活躍狀态的訂閱者。
此時,LiveData會認為訂閱者的生命周期處于STARTED或RESUMED狀态時,該訂閱者是活躍的,那麼如何使用 StockLiveData 類呢,如下所示。
public class MyFragment extends Fragment {
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
LiveData<BigDecimal> myPriceListener = ...;
myPriceListener.observe(getViewLifeycleOwner(), price -> {
// Update the UI.
});
}
}
複制
以Fragment作LifecycleOwner的執行個體傳遞到observer()方法中,這樣就将Observer綁定到擁有生命周期的擁有者。由于LiveData可以在多個Activity、Fragment和Service中使用,是以可以建立單例模式。
public class StockLiveData extends LiveData<BigDecimal> {
private static StockLiveData sInstance;
private StockManager stockManager;
private SimplePriceListener listener = new SimplePriceListener() {
@Override
public void onPriceChanged(BigDecimal price) {
setValue(price);
}
};
@MainThread
public static StockLiveData get(String symbol) {
if (sInstance == null) {
sInstance = new StockLiveData(symbol);
}
return sInstance;
}
private StockLiveData(String symbol) {
stockManager = new StockManager(symbol);
}
@Override
protected void onActive() {
stockManager.requestPriceUpdates(listener);
}
@Override
protected void onInactive() {
stockManager.removeUpdates(listener);
}
}
複制
然後,我們就可以在 Fragment 中使用它,如下所示。
public class MyFragment extends Fragment {
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
StockLiveData.get(symbol).observe(getViewLifecycleOwner(), price -> {
// Update the UI.
});
}
}
複制
3.2.5 轉換 LiveData
有時候,我們希望在把資料分發給觀察者之前進行一些處理,或者傳回一個基于已有值的LiveData對象的另外一個LiveData對象,此時就會用到 Transformations類。轉化LiveData時需要用到Transformations.map()和Transformations.switchMap()等方法。
Transformations.map()
例如,下面是使用Transformations.map()方法處理LiveData存儲的資料,然後将其傳遞給下遊的示例代碼。
LiveData<User> userLiveData = ...;
LiveData<String> userName = Transformations.map(userLiveData, user -> {
user.name + " " + user.lastName
});
複制
Transformations.switchMap()
使用Transformations.switchMap()方法同樣可以改變LiveData下遊的結果,但傳遞給switchMap()函數的必須是一個LiveData對象,如下所示。
private LiveData<User> getUser(String id) {
...;
}
LiveData<String> userId = ...;
LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );
複制
不過,這種轉換方式是惰性的,也就是隻有Observer來訂閱資料的時候,才會進行轉換。是以,當在ViewModel中使用一個Lifecycle對象,這種轉換是一種很好的解決方案。例如,假設您有一個界面元件,該元件接受位址并傳回該位址的郵政編碼,那麼我們可以使用switchMap()方法進行轉化。
class MyViewModel extends ViewModel {
private final PostalCodeRepository repository;
private final MutableLiveData<String> addressInput = new MutableLiveData();
public final LiveData<String> postalCode =
Transformations.switchMap(addressInput, (address) -> {
return repository.getPostCode(address);
});
public MyViewModel(PostalCodeRepository repository) {
this.repository = repository
}
private void setInput(String address) {
addressInput.setValue(address);
}
}
複制
四、LiveData工作原理
通過前面的介紹,我們知道LiveData是一個可觀察的資料持有者,并且它是具有元件生命周期感覺能力的,那它是如何觀察元件生命周期變化的呢?同時,LiveData僅更新處于活躍生命周期狀态的應用元件觀察者,也即是說LiveData并不會通知所有的觀察者,它隻會通知處于活躍狀态的觀察者,那麼它是如何做到這一點的呢?
LiveData生命周期變化觀察
前面介紹LiveData用法的時候提到,首先,我們建立 LiveData 執行個體,然後調用LiveData的observe方法來注冊觀察者,将ViewModel和LiveData關聯起來。observe()方法的源碼如下。
@MainThread
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);
}
複制
可以發現,observe首先會判斷元件目前的狀态,如果狀态為DESTROYED,那麼直接return,這說明DESTROYED狀态的元件是不允許注冊的。然後,建立一個LifecycleBoundObserver包裝類,将owner和observer傳了進去。接下來,将observer和LifecycleBoundObserver存儲到
SafeIterableMap<Observer<? super T>, ObserverWrapper>mObservers
中,注意,此處使用的是putIfAbsent方法,接下來對傳入的值進行判斷,如果傳入key對應的value已經存在,就傳回存在的value,不進行替換,如果不存在就添加key和value,傳回null。
最後,通過
owner.getLifecycle().addObserver()
方法将LifecycleBoundObserver添加到Lifecycle中完成注冊,這樣處理之後LiveData就有了觀察元件生命周期變化的能力。
LifecycleBoundObservers
LifecycleBoundObservers是LiveData的内部類,源碼如下。
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() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull 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實作了GenericLifecycleObserver接口,當元件狀态發生變化時,會調用onStateChanged方法,當元件處于DESTROYED狀态時,會調用removeObserver方法移除observer。
而LifecycleBoundObserver繼承了ObserverWrapper類,需要重寫shouldBeActive方法,用于判斷目前傳入的元件的狀态是否是Active狀态,即處于STARTED和RESUMED狀态。
ObserverWrapper
ObserverWrapper是Observer的包裝類,LiveData的生命周期狀态監聽activeStateChanged方法就定義在抽象類ObserverWrapper中,源碼如下。
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;
}
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);
}
}
}
複制
activeStateChanged()方法會根據Active狀态和處于Active狀态的元件的數量,來對onActive方法和onInactive方法進行回調,我們可以使用這兩個方法拓展LiveData對象。如果生命周期狀态是Active狀态,那麼會調用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<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
複制
mDispatchingValue用于标記目前是否處于分發狀态中,如果處于分發狀态就會進行狀态的分發,并最終調用considerNotify方法進行消息的分發,代碼如下所示。
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
//noinspection unchecked
observer.mObserver.onChanged((T) mData);
}
複制
considerNotify方法中做了多次的判斷,首先,判斷ObserverWrapper的mActive值如果不為true就直接return。然後,判斷目前observer對應元件的狀态是不是Active,如果不是就會再次調用activeStateChanged方法并傳入false,其方法内部會再次判斷是否執行onActive方法和onInactive方法回調。如果判斷條件都滿足就繼續調用Observer的onChanged方法,這個方法正是使用LiveData的observe方法的回調。