* 使用 LiveData 的優(yōu)點
* 使用 LiveData 對象
* 創(chuàng)建 LiveData 對象
* 觀察 LiveData 對象
* 更新 LiveData 對象
* LiveData 與 Room 一起使用
* 擴展 LiveData
* 轉(zhuǎn)換 LiveData
* 創(chuàng)建新的轉(zhuǎn)換
* 合并多個 LiveData 源
* 其他資源
LiveData 是一個可觀察的數(shù)據(jù)持有者類础爬。與常規(guī) observable 不同漏益,LiveData 是生命周期感知的憎乙,這意味著它尊重其他應(yīng)用程序組件的生命周期拟杉,例如 activity笑旺,fragment 或 service。此感知確保 LiveData 僅更新處于活動狀態(tài)的應(yīng)用組件觀察者范咨。
注意:要將 LiveData 組件導(dǎo)入 Android 項目故觅,請參閱 Adding Components to your Project。
如果 Observer 類表示的觀察者生命周期處于 STARTED
或 RESUMED
狀態(tài)渠啊,則 LiveData 會將其視為活動狀態(tài)输吏。LiveData 僅通知處于活動狀態(tài)的觀察者更新信息。非活動狀態(tài)的觀察者不會收到有關(guān)數(shù)據(jù)更改的通知替蛉。
你可以注冊與實現(xiàn)了 LifecycleOwner
接口的對象配對的觀察者贯溅。此關(guān)系允許在相應(yīng) Lifecycle
對象的狀態(tài)更改為 DESTROYED
時刪除觀察者拄氯。這對于 activity 和 fragment 特別有用,因為它們可以安全地觀察 LiveData 對象而不用擔(dān)心泄漏 - activity 和 fragment 在其生命周期被銷毀時立即取消訂閱它浅。
一译柏、使用 LiveData 的優(yōu)點
使用 LiveData 具有以下優(yōu)勢:
確保你的 UI 符合你的數(shù)據(jù)狀態(tài)
LiveData 遵循觀察者模式。生命周期狀態(tài)更改時姐霍,LiveData 會通知 Observer 對象鄙麦。你的觀察者可以在每次數(shù)據(jù)更改時更新 UI。
沒有內(nèi)存泄漏
觀察者綁定到 Lifecycle 對象镊折,并在其相關(guān)生命周期被銷毀后自行清理胯府。
不會因為 activity 停止而發(fā)生崩潰
如果觀察者的生命周期處于非活動狀態(tài)(例如,activity 在后臺堆棧中)恨胚,則它不會接收任何 LiveData 事件骂因。
不再需要手動處理生命周期
UI 組件只是觀察相關(guān)數(shù)據(jù),不會停止或恢復(fù)觀察赃泡。LiveData 自動管理所有這些寒波,因為它在觀察時意識到相關(guān)的生命周期狀態(tài)變化。
始終保持最新數(shù)據(jù)
如果生命周期變?yōu)榉腔顒訝顟B(tài)升熊,它將在再次變?yōu)榛顒訝顟B(tài)時接收最新數(shù)據(jù)俄烁。例如,后臺 activity 在返回前臺后立即接收最新數(shù)據(jù)级野。
適當(dāng)?shù)呐渲酶?/h6>
如果由于配置更改(例如設(shè)備旋轉(zhuǎn))而重新創(chuàng)建 activity 或 fragment猴娩,則會立即接收最新的可用數(shù)據(jù)。
共享資源
你可以使用單例模式擴展 LiveData 對象以包裝系統(tǒng)服務(wù)勺阐,以便可以在應(yīng)用程序中共享它們卷中。LiveData 對象連接到系統(tǒng)服務(wù)一次,然后任何需要該資源的觀察者只需觀察 LiveData 對象渊抽。
二蟆豫、使用 LiveData 對象
請按照以下步驟使用 LiveData 對象:
創(chuàng)建 LiveData 實例以保存特定類型的數(shù)據(jù)。這通常在 ViewModel 類中完成懒闷。
創(chuàng)建一個 Observer 對象十减,該對象定義
onChanged()
方法,該方法控制 LiveData 對象數(shù)據(jù)更改時觸發(fā)的邏輯愤估。通常在 UI 控制器中創(chuàng)建一個 Observer 對象帮辟,例如 activity 或 fragment。使用
observe()
方法將 Observer 對象關(guān)聯(lián)到 LiveData 對象玩焰。observe()
方法需要LifecycleOwner
對象由驹。該方法使 Observer 對象訂閱 LiveData 對象,以便通知它更改昔园。通常將 Observer 對象關(guān)聯(lián)到 UI 控制器中蔓榄,例如 activity 或 fragment并炮。
注意:你可以使用
observeForever(Observer)
方法注冊沒有關(guān)聯(lián)任何一個LifecycleOwner
對象的觀察者。在這種情況下甥郑,觀察者被認為始終處于活動狀態(tài)逃魄,因此始終會收到有關(guān)修改的通知。你可以刪除這些觀察者通過調(diào)用removeObserver(Observer)
方法澜搅。
更新存儲在 LiveData 對象中的值時伍俘,只要關(guān)聯(lián)的 LifecycleOwner
處于活動狀態(tài),它就會觸發(fā)所有已注冊的觀察者勉躺。
LiveData 允許 UI 控制器觀察者訂閱更新养篓。當(dāng) LiveData 對象保存的數(shù)據(jù)發(fā)生更改時,UI 會自動響應(yīng)更新赂蕴。
2.1 創(chuàng)建 LiveData 對象
LiveData 是一個包裝器,可以與任何數(shù)據(jù)一起使用舶胀,包括實現(xiàn)集合的對象概说,例如 List。LiveData
對象通常存儲在 ViewModel
對象中嚣伐,并通過 getter
方法訪問糖赔,如以下示例所示:
public class NameViewModel extends ViewModel {
// Create a LiveData with a String
private MutableLiveData<String> currentName;
public MutableLiveData<String> getCurrentName() {
if (currentName == null) {
currentName = new MutableLiveData<String>();
}
return currentName;
}
// Rest of the ViewModel...
}
最初的時候并沒有設(shè)置 LiveData 對象中的數(shù)據(jù)。
注意:確保在 ViewModel 對象中存儲用于更新 UI 的 LiveData 對象轩端,而不是在 activity 或 fragment 中放典,原因如下:
避免臃腫的 activity 和 fragment。UI 控制器負責(zé)顯示數(shù)據(jù)但不保持?jǐn)?shù)據(jù)狀態(tài)基茵。
將 LiveData 實例與特定 activity 或 fragment 實例分離奋构,并允許 LiveData 對象在配置更改后繼續(xù)存活。
你可以在 ViewModel 指南中閱讀有關(guān) ViewModel 類的優(yōu)點和用法的更多信息拱层。
2.2 觀察 LiveData 對象
在大多數(shù)情況下弥臼,app 組件的 onCreate()
方法是開始觀察 LiveData 對象的正確位置,原因如下:
確保系統(tǒng)不會從 activity 或 fragment 的
onResume()
方法進行冗余調(diào)用根灯。確保 activity 或 fragment 在其變?yōu)榛顒訝顟B(tài)時立即顯示數(shù)據(jù)径缅。只要應(yīng)用程序組件處于
STARTED
狀態(tài),它就會從它正在觀察的 LiveData 對象中接收最新值烙肺。只有在設(shè)置了要觀察的 LiveData 對象時才會出現(xiàn)這種情況纳猪。
通常,LiveData 僅在數(shù)據(jù)更改時才提供更新桃笙,并且要求觀察者處于活動狀態(tài)氏堤。此行為的一個例外是觀察者從非活動狀態(tài)更改為活動狀態(tài)時也會收到更新。此外搏明,如果觀察者第二次從非活動狀態(tài)更改為活動狀態(tài)丽猬,則只有在自上次活動狀態(tài)以來該值發(fā)生更改時才會收到更新宿饱。
以下示例代碼說明了如何開始觀察 LiveData 對象:
public class NameActivity extends AppCompatActivity {
private NameViewModel model;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Other code to setup the activity...
// Get the ViewModel.
model = ViewModelProviders.of(this).get(NameViewModel.class);
// Create the observer which updates the UI.
final Observer<String> nameObserver = new Observer<String>() {
@Override
public void onChanged(@Nullable final String newName) {
// Update the UI, in this case, a TextView.
nameTextView.setText(newName);
}
};
// Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
model.getCurrentName().observe(this, nameObserver);
}
}
在使用 nameObserver
作為參數(shù)傳遞調(diào)用 observe()
之后,立即調(diào)用 onChanged()
脚祟,提供存儲在 mCurrentName
中的最新值谬以。如果 LiveData
對象未在 mCurrentName
中設(shè)置值,則不會調(diào)用 onChanged()
由桌。
2.3 更新 LiveData 對象
LiveData 沒有公開的方法來更新存儲的數(shù)據(jù)为黎。MutableLiveData
類公開 setValue(T)
和 postValue(T)
方法,如果需要編輯存儲在 LiveData 對象中的值行您,則必須使用這些方法铭乾。通常在 ViewModel 中使用 MutableLiveData
,然后 ViewModel 僅向觀察者公開不可變的 LiveData 對象娃循。
設(shè)置觀察者關(guān)系后炕檩,可以更新 LiveData 對象的值,如以下示例所示捌斧,當(dāng)用戶點擊按鈕時觸發(fā)所有觀察者:
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String anotherName = "John Doe";
model.getCurrentName().setValue(anotherName);
}
});
在示例中調(diào)用 setValue(T)
會導(dǎo)致觀察者使用值 John Doe 調(diào)用其 onChanged()
方法笛质。該示例顯示按下按鈕,調(diào)用 setValue()
或 postValue()
來更新 mName捞蚂,更新的原因可以有多種妇押,包括響應(yīng)網(wǎng)絡(luò)請求或數(shù)據(jù)庫加載完成;在所有情況下姓迅,對 setValue()
或 postValue()
的調(diào)用都會觸發(fā)觀察者并更新 UI敲霍。
注意:必須調(diào)用
setValue(T)
方法才能從主線程更新 LiveData 對象。如果代碼在工作線程中執(zhí)行丁存,則可以使用postValue(T)
方法來更新 LiveData 對象肩杈。
2.4 LiveData 與 Room 一起使用
Room 持久性庫支持可觀察的查詢,這些查詢返回 LiveData
對象解寝》嫣瘢可觀察查詢作為數(shù)據(jù)庫訪問對象 (DAO) 的一部分寫入。
在更新數(shù)據(jù)庫時编丘,Room 會生成更新 LiveData 對象所需的所有代碼与学。生成的代碼在需要時在后臺線程上異步運行查詢。此模式對于使 UI 中顯示的數(shù)據(jù)與存儲在數(shù)據(jù)庫中的數(shù)據(jù)保持同步非常有用嘉抓。你可以在 Room 持久性庫指南中閱讀有關(guān) Room 和 DAO 的更多信息索守。
三、擴展 LiveData
如果觀察者的生命周期處于 STARTED
或 RESUMED
狀態(tài)抑片,LiveData 會將觀察者視為處于活動狀態(tài)卵佛。以下示例代碼說明了如何擴展 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);
}
}
此示例中價格監(jiān)聽器的實現(xiàn)包括以下重要方法:
當(dāng)
LiveData
對象具有活動的觀察者時,將調(diào)用onActive()
方法。這意味著你需要從此方法開始觀察股票價格更新截汪。當(dāng)
LiveData
對象沒有任何活動的觀察者時疾牲,將調(diào)用onInactive()
方法。由于沒有觀察者正在觀察衙解,因此沒有理由保持與 StockManager 服務(wù)的連接阳柔。setValue(T)
方法更新 LiveData 實例的值,并通知任何處于活動狀態(tài)的觀察者有關(guān)更改的信息蚓峦。
你可以如下所示使用 StockLiveData 類:
public class MyFragment extends Fragment {
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
LiveData<BigDecimal> myPriceListener = ...;
myPriceListener.observe(this, price -> {
// Update the UI.
});
}
}
observe()
方法將 fragment(LifecycleOwner
的一個實例)作為第一個參數(shù)傳遞舌剂。這樣做表示此觀察者綁定到與所有者關(guān)聯(lián)的 Lifecycle
對象,這意味著:
如果
Lifecycle
對象未處于活動狀態(tài)暑椰,則即使值發(fā)生更改霍转,也不會調(diào)用觀察者。銷毀
Lifecycle
對象后一汽,會自動刪除觀察者避消。
LiveData 對象具有生命周期感知這一事實意味著你可以在多個 activity,fragment 和 service 之間共享它們召夹。為了簡化示例岩喷,你可以將 LiveData 類實現(xiàn)為單例,如下所示:
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 onActivityCreated(Bundle savedInstanceState) {
StockLiveData.get(symbol).observe(this, price -> {
// Update the UI.
});
}
}
多個 fragment 和 activity 可以觀察 MyPriceListener 實例。LiveData 僅在一個或多個 fragment 和 activity 可見且處于活動狀態(tài)時才連接到系統(tǒng)服務(wù)昏兆。
四枫虏、轉(zhuǎn)換 LiveData
你可能希望在將其分配給觀察者之前更改存儲在 LiveData 對象中的值,或者你可能需要根據(jù)另一個實例返回另一個 LiveData 實例的值爬虱。Lifecycle 包提供 Transformations 類隶债,其中包括支持這些場景的幫助方法。
對存儲在 LiveData
對象中的值應(yīng)用函數(shù)跑筝,并往后傳遞結(jié)果死讹。
LiveData<User> userLiveData = ...;
LiveData<String> userName = Transformations.map(userLiveData, user -> {
user.name + " " + user.lastName
});
與 map()
類似,將函數(shù)應(yīng)用于存儲在 LiveData 對象中的值曲梗,并將結(jié)果解包并向下分發(fā)赞警。傳遞給 switchMap()
的函數(shù)必須返回一個 LiveData 對象,如以下示例所示:
private LiveData<User> getUser(String id) {
...;
}
LiveData<String> userId = ...;
LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );
你可以使用轉(zhuǎn)換方法在觀察者的生命周期中傳遞信息虏两。除非觀察者正在觀察返回的 LiveData 對象愧旦,否則不會執(zhí)行轉(zhuǎn)換。由于轉(zhuǎn)換是延遲執(zhí)行的定罢,因此生命周期相關(guān)的行為會被隱式傳遞下去笤虫,而不需要額外的顯式調(diào)用或依賴項。
如果你認為在 ViewModel 對象中需要 Lifecycle
對象,則轉(zhuǎn)換可能是更好的解決方案琼蚯。例如酬凳,假設(shè)你有一個接受地址的 UI 組件并返回該地址的郵政編碼。你可以為此組件實現(xiàn)樸素的 ViewModel
(不推薦)遭庶,如以下示例代碼所示:
class MyViewModel extends ViewModel {
private final PostalCodeRepository repository;
public MyViewModel(PostalCodeRepository repository) {
this.repository = repository;
}
private LiveData<String> getPostalCode(String address) {
// DON'T DO THIS
return repository.getPostCode(address);
}
}
UI 組件需要從先前的 LiveData 對象取消注冊宁仔,并在每次調(diào)用 getPostalCode()
時注冊到新實例。此外罚拟,如果重新創(chuàng)建 UI 組件台诗,它將觸發(fā)對 repository.getPostCode()
方法的另一次調(diào)用,而不是使用先前調(diào)用的結(jié)果赐俗。
相反拉队,你可以將郵政編碼查找實現(xiàn)為地址輸入的轉(zhuǎn)換,如以下示例所示:
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);
}
}
在這種情況下阻逮,postalCode 字段被定義為 addressInput 的轉(zhuǎn)換粱快。只要你的應(yīng)用程序具有與 postalCode 字段關(guān)聯(lián)的處于活動狀態(tài)的觀察者,只要 addressInput 更改叔扼,就會重新計算并檢索字段的值事哭。
此機制允許較低級別的應(yīng)用程序創(chuàng)建按需延遲計算的 LiveData
對象。ViewModel
對象可以輕松獲取對 LiveData
對象的引用瓜富,然后在它們之上定義轉(zhuǎn)換規(guī)則鳍咱。
4.1 創(chuàng)建新的轉(zhuǎn)換
有十幾種不同的特定轉(zhuǎn)換可能對你的應(yīng)用有用,但默認情況下不提供与柑。 要實現(xiàn)自己的轉(zhuǎn)換谤辜,可以使用 MediatorLiveData
類,該類偵聽其他 LiveData 對象并處理它們發(fā)出的事件价捧。MediatorLiveData
正確地將其狀態(tài)傳遞到源 LiveData 對象丑念。 要了解有關(guān)此模式的更多信息,請參閱 Transformations 類的參考文檔结蟋。
五脯倚、合并多個 LiveData 源
MediatorLiveData
是 LiveData
的子類,允許你合并多個 LiveData
源嵌屎。只要任何原始 LiveData
源對象發(fā)生更改推正,就會觸發(fā) MediatorLiveData
對象的觀察者。
例如宝惰,如果你的 UI 中的 LiveData
對象舔稀,可以從本地數(shù)據(jù)庫或網(wǎng)絡(luò)進行更新,那么你可以添加以下來源的 MediatorLiveData
對象:
與存儲在數(shù)據(jù)庫中的數(shù)據(jù)關(guān)聯(lián)的
LiveData
對象掌测。與從網(wǎng)絡(luò)訪問的數(shù)據(jù)關(guān)聯(lián)的
LiveData
對象内贮。
你的 activity 只需要觀察 MediatorLiveData
對象以從兩個源接收更新产园。有關(guān)詳細示例,請參閱 Guide to App Architecture 中的 Addendum: exposing network status夜郁。
六什燕、其他資源
LiveData
用于 Sunflower 演示應(yīng)用程序。
另請參閱架構(gòu)組件 BasicSample竞端。
有關(guān)將 LiveData 與 Snackbar 消息屎即,導(dǎo)航事件和其他事件一起使用的其他信息,請閱讀此文章事富。