livedata 是一個資料持有者類,它持有一個值并允許觀察該值。不同于普通的可觀察者,livedata 遵守應用程式元件的生命周期,以便 observer 可以指定一個其應該遵守的 lifecycle。
如果 observer 的 lifecycle 處于 started 或 resumed 狀态,livedata 會認為 observer 處于活動狀态。
public class locationlivedata extends livedata<location> {
private locationmanager locationmanager;
private simplelocationlistener listener = new simplelocationlistener() {
@override
public void onlocationchanged(location location) {
setvalue(location);
}
};
public locationlivedata(context context) {
locationmanager = (locationmanager) context.getsystemservice(
context.location_service);
}
@override
protected void onactive() {
locationmanager.requestlocationupdates(locationmanager.gps_provider, 0, 0, listener);
protected void oninactive() {
locationmanager.removeupdates(listener);
}
location 監聽的實作有 3 個重要部分:
onactive():當 livedata 有一個處于活動狀态的觀察者時該方法被調用,這意味着需要開始從裝置觀察位置更新。
voninactive():當 livedata 沒有任何處于活動狀态的觀察者時該方法被調用。由于沒有觀察者在監聽,是以沒有理由保持與 locationmanager 的連接配接。這是非常重要的,因為保持連接配接會顯著消耗電量并且沒有任何好處。
setvalue():調用該方法更新 livedata 執行個體的值,并将此變更通知給處于活動狀态的觀察者。
可以像下面這樣使用新的 locationlivedata:
public class myfragment extends lifecyclefragment {
public void onactivitycreated (bundle savedinstancestate) {
livedata<location> mylocationlistener = ...;
util.checkuserstatus(result -> {
if (result) {
mylocationlistener.addobserver(this, location -> {
// update ui
});
}
});
請注意,addobserver() 方法将 lifecycleowner 作為第一個參數傳遞。這樣做表示該觀察者應該綁定到 lifecycle,意思是:
如果 lifecycle 不處于活動狀态(started 或 resumed),即使該值發生變化也不會調用觀察者。
如果 lifecycle 被銷毀,那麼自動移除觀察者。
livedata 是生命周期感覺的事實給我們提供了一個新的可能:可以在多個 activity,fragment 等之間共享它。為了保持執行個體簡單,可以将其作為單例,如下所示:
private static locationlivedata sinstance;
@mainthread
public static locationlivedata get(context context) {
if (sinstance == null) {
sinstance = new locationlivedata(context.getapplicationcontext());
return sinstance;
private locationlivedata(context context) {
現在 fragment 可以像下面這樣使用它:
locationlivedata.get(getactivity()).observe(this, location -> {
// update ui
}
可能會有多個 fragment 和 activity 在觀察 mylocationlistener 執行個體,livedata 可以規範的管理它們,以便隻有當它們中的任何一個可見(即處于活動狀态)時才連接配接到系統服務。
livedata 有以下優點:
沒有記憶體洩漏:因為 observer 被綁定到它們自己的 lifecycle 對象上,是以,當它們的 lifecycle 被銷毀時,它們能自動的被清理。
不會因為 activity 停止而崩潰:如果 observer 的 lifecycle 處于閑置狀态(例如:activity 在背景時),它們不會收到變更事件。
始終保持資料最新:如果 lifecycle 重新啟動(例如:activity 從背景傳回到啟動狀态)将會收到最新的位置資料(除非還沒有)。
正确處理配置更改:如果 activity 或 fragment 由于配置更改(如:裝置旋轉)重新建立,将會立即收到最新的有效位置資料。
資源共享:可以隻保留一個 mylocationlistener 執行個體,隻連接配接系統服務一次,并且能夠正确的支援應用程式中的所有觀察者。
不再手動管理生命周期:fragment 隻是在需要的時候觀察資料,不用擔心被停止或者在停止之後啟動觀察。由于 fragment 在觀察資料時提供了其 lifecycle,是以 livedata 會自動管理這一切。
livedata 的轉換
有時候可能會需要在将 livedata 發送到觀察者之前改變它的值,或者需要更具另一個 livedata 傳回一個不同的 livedata 執行個體。
lifecycle 包提供了一個 transformations 類包含對這些操作的幫助方法。
,%20android.arch.core.util.function
livedata<user> userlivedata = ...;
livedata<string> username = transformations.map(userlivedata, user -> {
user.name + " " + user.lastname
});
private livedata<user> getuser(string id) {
...;
}
livedata<string> userid = ...;
livedata<user> user = transformations.switchmap(userid, id -> getuser(id) );
使用這些轉換允許在整個調用鍊中攜帶觀察者的 lifecycle 資訊,以便隻有在觀察者觀察到 livedata 的傳回時才運算這些轉換。轉換的這種惰性運算性質允許隐式的傳遞生命周期相關行為,而不必添加顯式的調用或依賴。
每當你認為在 viewmodel 中需要一個 lifecycle 類時,轉換可能是解決方案。
例如:假設有一個 ui,使用者輸入一個位址然後會收到該位址的郵政編碼。該 ui 簡單的 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 登出并且在每次調用 getpostalcode() 時重新注冊到新的執行個體。此外,如果 ui 被重新建立,它将會觸發新的 repository.getpostcode() 調用,而不是使用之前的調用結果。
不能使用那種方式,而應該實作将位址輸入轉換為郵政編碼資訊。
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 字段為 public final,因為它永遠不會改變。postalcode 被定義為 addressinput 的轉換,是以當 addressinput 改變時,如果有處于活動狀态的觀察者,repository.getpostcode() 将會被調用。如果在調用時沒有處于活動狀态的觀察者,在添加觀察者之前不會進行任何運算。
該機制允許以較少的資源根據需要惰性運算來建立 livedata。viewmodel 可以輕松擷取到 livedata 并在它們上面定義轉換規則。
建立新的轉換
在應用程式中可能會用到十幾種不同的特定轉換,但是預設是不提供的。可以使用 mediatorlivedata 實作自己的轉換,mediatorlivedata 是為了用來正确的監聽其它 livedata 執行個體并處理它們發出的事件而特别建立的。mediatorlivedata 需要特别注意正确的向源 livedata 傳遞其處于活動/閑置狀态。有關詳細資訊,請參閱 transformations 類。
本文作者:佚名
來源:51cto