最近研究了一下Architecture Components趁猴,嘗試用這個架構(gòu)寫了一個小demo刊咳,發(fā)現(xiàn)了一些問題,也有了一些心得儡司,想分享給大家娱挨。
以下關(guān)于LiveData的基礎(chǔ)使用摘自:[譯] Architecture Components 之 LiveData
LiveData
LiveData 是一個數(shù)據(jù)持有者類,它持有一個值并允許觀察該值捕犬。不同于普通的可觀察者跷坝,LiveData 遵守應(yīng)用程序組件的生命周期酵镜,以便 Observer 可以指定一個其應(yīng)該遵守的 Lifecycle。
LiveData主要方法
- onActive()
當(dāng) LiveData 有一個處于活動狀態(tài)的觀察者時該方法被調(diào)用柴钻,這意味著需要開始從設(shè)備觀察位置更新淮韭。
- onInactive()
當(dāng) LiveData 沒有任何處于活動狀態(tài)的觀察者時該方法被調(diào)用。由于沒有觀察者在監(jiān)聽贴届,所以沒有理由保持與 LocationManager 的連接靠粪。這是非常重要的,因?yàn)楸3诌B接會顯著消耗電量并且沒有任何好處毫蚓。
- setValue()
調(diào)用該方法更新 LiveData 實(shí)例的值占键,并將此變更通知給處于活動狀態(tài)的觀察者。
可以通過addObserver
添加數(shù)據(jù)的觀察者來更新界面绍些,展示新的數(shù)據(jù)捞慌。
liveData.addObserver(this, location -> {
// 更新 UI
});
請注意,addObserver() 方法將 LifecycleOwner 作為第一個參數(shù)傳遞(即Activity或者Fragment)柬批。這樣做表示該觀察者應(yīng)該綁定到 Lifecycle,意思是:
如果 Lifecycle 不處于活動狀態(tài)(STARTED 或 RESUMED)袖订,即使該值發(fā)生變化也不會調(diào)用觀察者氮帐。
如果 Lifecycle 被銷毀,那么自動移除觀察者洛姑。
LiveData 有以下優(yōu)點(diǎn):
沒有內(nèi)存泄漏:因?yàn)?Observer 被綁定到它們自己的 Lifecycle 對象上上沐,所以,當(dāng)它們的 Lifecycle 被銷毀時楞艾,它們能自動的被清理参咙。
不會因?yàn)?activity 停止而崩潰:如果 Observer 的 Lifecycle 處于閑置狀態(tài)(例如:activity 在后臺時),它們不會收到變更事件硫眯。
始終保持?jǐn)?shù)據(jù)最新:如果 Lifecycle 重新啟動(例如:activity 從后臺返回到啟動狀態(tài))將會收到最新的位置數(shù)據(jù)(除非還沒有)蕴侧。
正確處理配置更改:如果 activity 或 fragment 由于配置更改(如:設(shè)備旋轉(zhuǎn))重新創(chuàng)建,將會立即收到最新的有效位置數(shù)據(jù)两入。
資源共享:可以只保留一個 MyLocationListener 實(shí)例净宵,只連接系統(tǒng)服務(wù)一次,并且能夠正確的支持應(yīng)用程序中的所有觀察者裹纳。
不再手動管理生命周期你可能已經(jīng)注意到择葡,fragment 只是在需要的時候觀察數(shù)據(jù),不用擔(dān)心被停止或者在停止之后啟動觀察剃氧。由于 fragment 在觀察數(shù)據(jù)時提供了其 Lifecycle敏储,所以 LiveData 會自動管理這一切。
問題
看了以上的介紹朋鞍,發(fā)現(xiàn)LiveData還是非常好用的已添,等同于以前用rxLifecycle來管理生命周期妥箕,但是在實(shí)際使用的時候就發(fā)現(xiàn)問題了,LiveData只能傳遞一個值酝碳,之前我們用Retrofit+OkHttp+rxJava等構(gòu)建MVP模式的應(yīng)用時矾踱,網(wǎng)絡(luò)數(shù)據(jù)請求經(jīng)常會有多種結(jié)果:(1)正常返回?cái)?shù)據(jù),(2)接口返回疏哗,錯誤結(jié)果(3)網(wǎng)絡(luò)請求失敗 (4)列表無更多數(shù)據(jù)(5)接口正常返回呛讲,無數(shù)據(jù) 。返奉。贝搁。等等情況,之前我們會在Presenter層通過回調(diào)獲得這些發(fā)生在Model層的情況芽偏,然后調(diào)用View層改變界面的方法展示給用戶雷逆,但是使用LiveData時View層可以直接通過ViewModel獲得Model提供的LiveData,有數(shù)據(jù)時可以正常顯示污尉,但是異常時就顯得力不從心了膀哲,我們只能傳遞一個值:有值或者null,無法判斷復(fù)雜的具體的情況被碗。
上圖是官方提供的Architecture Components架構(gòu)示意圖某宪,其中的依賴關(guān)系應(yīng)該是單向的(隱藏的觀察、被觀察的關(guān)系不算)锐朴,即Activity/Fragment持有ViewModel的引用兴喂,ViewModel持有Repository,提供LiveData焚志。衣迷。。官方也提到ViewModel僅僅是一個LiveData的容器酱酬,不應(yīng)該持有Activity/Fragment的引用壶谒。
基于以上這種情況下如何根據(jù)不同的情況改變界面那?例如:彈出吐司岳悟,對話框佃迄,顯示網(wǎng)絡(luò)異常等等那?贵少?呵俏?啰嗦了這么半天,終于引出今天的話題——擴(kuò)展LiveData 以滿足需求滔灶。
擴(kuò)展
先來分析一下LiveData普碎,當(dāng)添加了觀察者,一旦調(diào)用setValue方法录平,觀察者的onChanged方法就會接受到新的值麻车。傳遞的值是通過LiveData<T>
泛型定義缀皱。
既然是要區(qū)分類型,一開始的思路是將泛型定義成自定義的ActionEntity<T>
动猬,有點(diǎn)類似網(wǎng)絡(luò)接口返回啤斗,id區(qū)分類型,extra附帶額外數(shù)據(jù)赁咙,original是原始的value數(shù)據(jù)钮莲,即將真實(shí)數(shù)據(jù)包裝一層,通過id來區(qū)分不同的情況:
public class ActionEntity<T> {
public static final int ACTION = 0x1;
public static final int VALUE = 0x2;
public int type;
public int id;
public Object[] extra;
public T original;
public ActionEntity(T original) {
this.original = original;
type = VALUE;
}
public ActionEntity(int id, Object[] extra) {
this.id = id;
this.extra = extra;
type = ACTION;
}
}
接下來就是修改LiveData的setValue方法實(shí)現(xiàn)自動裝包彼水,讓使用時感知不到包裝的存在
import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.MediatorLiveData;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
/**
* Created by hubert
* <p>
* Created on 2017/12/7.
*/
public class ActionLiveData2<T> extends MediatorLiveData<ActionEntity<T>> implements ActionCreator {
@Override
public void setAction(int id, Object... args) {
super.setValue(new ActionEntity<T>(id, args));
}
public void setValue_(T value) {
super.setValue(new ActionEntity<T>(value));
}
public void postValue_(T value) {
super.postValue(new ActionEntity<T>(value));
}
public void observe_(@NonNull LifecycleOwner owner, @NonNull ActionObserver2<T> observer) {
super.observe(owner, observer);
}
public void observeForever_(@NonNull ActionObserver2<T> observer) {
super.observeForever(observer);
}
public void removeObserver_(@NonNull ActionObserver2<T> observer) {
super.removeObserver(observer);
}
@Nullable
public T getValue_() {
ActionEntity<T> entity = super.getValue();
return entity == null ? null : entity.original;
}
}
修改Observer的onChanged方法實(shí)現(xiàn)自動拆包
import android.arch.lifecycle.Observer;
import android.support.annotation.Nullable;
/**
* Created by hubert
* <p>
* Created on 2017/12/7.
*/
public abstract class ActionObserver2<T> implements Observer<ActionEntity<T>>, ActionHandler {
@Override
public final void onChanged(@Nullable ActionEntity<T> entity) {
if (entity != null) {
if (entity.type == ActionEntity.VALUE) {
onChanged_(entity.original);
} else {
onAction(entity.id, entity.extra);
}
}
}
public abstract void onChanged_(T entity);
}
不知道你有沒有注意到很多方法最后都有_
崔拥,這是由于對T泛型的數(shù)據(jù)做了改變,新包裝的方法無法使用原方法名凤覆,只能通過添加下劃線來區(qū)別原方法链瓦。
這樣修改的話直接使用的話是能達(dá)到我的目的,但是通常情況下LiveData會通過Transformations進(jìn)行轉(zhuǎn)換盯桦,這時候泛型將很難定義慈俯,而且無法申明我們定義的類,因?yàn)門ransformations的switchMap方法返回的必須是LiveData<T>
拥峦,泛型只能定義成LiveData<ActionEntity<T>>
肥卡,雖然我的定義的ActionLiveData2<T>
也是繼承自LiveData<ActionEntity<T>>
,但是并不相等笆铝汀!>疚浮璃哟!
于是自己都寫不下去了?? 并且這樣的命名也非常的讓我不爽,于是廢棄了這種方式喊递。
接著我又有了一個想法??随闪,直接讓LiveData傳遞Action,就像傳遞Value一樣地傳遞:通過setAction設(shè)置事件骚勘,并且在Observer中onAction方法中接受事件作出處理铐伴。這個可以有!仿照value是怎么傳遞的不就行了嘛俏讹!??
然后我仔細(xì)分析了LiveData的源碼当宴,了解了其中是如何傳遞Value的,但是其中處理value的方法基本都是private的泽疆,子類無法使用户矢。因此,我只能按照同樣的邏輯來實(shí)現(xiàn)Action的傳遞:
import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MediatorLiveData;
import android.arch.lifecycle.Observer;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Created by hubert on 2017/12/6.
* <p>
*/
public class ActionLiveData<T> extends MutableLiveData<T> implements ActionCreator {
private Set<ActionObserver<T>> actionObservers = new HashSet<>();
private boolean active;//父類中有這個屬性殉疼,但是也是private
private ActionEntity actionEntity;
private Handler handler;
private Runnable actionRun = new Runnable() {
@Override
public void run() {
dispatchAction();
}
};
private void dispatchAction() {
if (active) {
for (ActionObserver<T> actionObserver : actionObservers) {
actionObserver.onAction(actionEntity.id, actionEntity.extra);
}
}
}
@Override
protected void onActive() {
super.onActive();
active = true;
}
@Override
protected void onInactive() {
super.onInactive();
active = false;
}
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
super.observe(owner, observer);
if (observer instanceof ActionObserver) {
actionObservers.add((ActionObserver<T>) observer);
}
}
@Override
public void removeObserver(@NonNull Observer<T> observer) {
super.removeObserver(observer);
if (observer instanceof ActionObserver) {
actionObservers.remove(observer);
}
}
/**
* 設(shè)置事件
* @param id 事件id
* @param args 可選的參數(shù)
*/
@Override
public void setAction(int id, Object... args) {
actionEntity = new ActionEntity(id, args);
if (isMainThread()) {
dispatchAction();
} else {
if (handler == null) {
handler = new Handler(Looper.getMainLooper());
}
handler.post(actionRun);
}
}
public boolean isMainThread() {
return Thread.currentThread() == Looper.getMainLooper().getThread();
}
Action相關(guān)接口的聲明:
public interface ActionCreator {
void setAction(int id, Object... args);
}
public interface ActionHandler {
void onAction(int id, Object... args);
}
public interface ActionObserver<T> extends Observer<T>, ActionHandler {
}
使用時傳入ActionObserver復(fù)寫onAction(int id, Object... args)接收Action事件
actionLiveData.observe(this, new ActionObserver<Integer>() {
@Override
public void onAction(int id, Object... args) {
if (id == 1) {
//do something
}
}
@Override
public void onChanged(@Nullable Integer integer) {
//the original value
}
});
完美梯浪!馬上把demo中的LiveData換成ActionLiveData跑上~ 沒有反應(yīng)??捌年,怎么可能,我的邏輯...應(yīng)該完美挂洛!?? 各種斷點(diǎn)找原因礼预,到底為什么沒有傳遞過來。虏劲。托酸。
最終被我發(fā)現(xià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);
}
}
我的LiveData是通過Transformations.switchMap進(jìn)行轉(zhuǎn)換伙单,或者說傳遞获高,即讓一個LiveData(view層中獲得的那個,我們簡稱小v)觀察另一個LiveData(M層生成的小m)吻育,請求數(shù)據(jù)只會改變小m的value念秧,switchMap
方法內(nèi)部其實(shí)就是給小m設(shè)置一個Observer,當(dāng)小m的value改變時會調(diào)用該Observer的onChanged方法布疼,在該方法中調(diào)用小v的setValue摊趾,這樣View層的Observer的onChanged方法就可以改變界面。
其中只處理了value的傳遞游两,并且返回的對象是方法內(nèi)部new的這個final MediatorLiveData<Y> result = new MediatorLiveData<>();
砾层,我們自己新添加的action當(dāng)然不會被傳遞啦。
??既然這樣贱案,那我們就自己傳遞吧肛炮。還是仿照MediatorLiveData中傳遞方式,新增一個ActionSource類:
/**
* Created by hubert on 2017/12/6.
* <p>
* LiveData本身只能有一種泛型的數(shù)據(jù)宝踪,在(接口)數(shù)據(jù)返回時只能設(shè)置有值或者null來判斷侨糟,
* 無法傳遞其他信息,如需要提示網(wǎng)絡(luò)瘩燥,數(shù)據(jù)錯誤等情況秕重,為每一種情況定義一個LiveData又太過于繁瑣。
* 基于以上考慮對LiveData進(jìn)行擴(kuò)展厉膀,使其支持傳遞自定義Action溶耘,
* 通過調(diào)用{@code setAction(int id, Object... args)}發(fā)送事件。
* 并在observe方法中傳入{@link ActionObserver}用于接收action事件作出處理服鹅。
* <pre>
* actionLiveData.observe(this, new ActionObserver<Integer>() {
* {@literal @}Override
* public void onAction(int id, Object... args) {
* if (id == 1) {
* //do something
* }
* }
*
* {@literal @}Override
* public void onChanged(@Nullable Integer integer) {
* //the original value
* }
* });
* </pre>
*/
public class ActionLiveData<T> extends MediatorLiveData<T> implements ActionCreator {
private Set<ActionObserver<T>> actionObservers = new HashSet<>();
private boolean active;
private ActionEntity actionEntity;
private Handler handler;
private Runnable actionRun = new Runnable() {
@Override
public void run() {
dispatchAction();
}
};
/**
* 通知Observer更新事件
*/
private void dispatchAction() {
if (active) {
for (ActionObserver<T> actionObserver : actionObservers) {
actionObserver.onAction(actionEntity.id, actionEntity.extra);
}
}
}
@Override
protected void onActive() {
super.onActive();
active = true;
for (Map.Entry<ActionLiveData<?>, ActionSource<?>> entry : mHandlers.entrySet()) {
entry.getValue().plug();
}
}
@Override
protected void onInactive() {
super.onInactive();
active = false;
for (Map.Entry<ActionLiveData<?>, ActionSource<?>> entry : mHandlers.entrySet()) {
entry.getValue().unplug();
}
}
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
super.observe(owner, observer);
if (observer instanceof ActionObserver) {
actionObservers.add((ActionObserver<T>) observer);
}
}
@Override
public void removeObserver(@NonNull Observer<T> observer) {
super.removeObserver(observer);
if (observer instanceof ActionObserver) {
actionObservers.remove(observer);
}
}
/**
* 設(shè)置事件
* @param id 事件id
* @param args 可選的參數(shù)
*/
@Override
public void setAction(int id, Object... args) {
actionEntity = new ActionEntity(id, args);
if (isMainThread()) {
dispatchAction();
} else {
if (handler == null) {
handler = new Handler(Looper.getMainLooper());
}
handler.post(actionRun);
}
}
public boolean isMainThread() {
return Thread.currentThread() == Looper.getMainLooper().getThread();
}
/****支持Transformations的轉(zhuǎn)換***/
private Map<ActionLiveData<?>, ActionSource<?>> mHandlers = new HashMap<>();
@Override
public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<S> onChanged) {
super.addSource(source, onChanged);
if (source instanceof ActionLiveData && onChanged instanceof ActionObserver) {
addActionObserver((ActionLiveData<S>) source, (ActionObserver<S>) onChanged);
}
}
protected <S> void addActionObserver(ActionLiveData<S> source, ActionObserver<S> actionObserver) {
ActionSource<S> actionSource = new ActionSource<>(source, actionObserver);
ActionSource<?> existing = mHandlers.put(source, actionSource);
if (existing != null) {
return;
}
if (hasActiveObservers()) {
actionSource.plug();
}
}
@Override
public <S> void removeSource(@NonNull LiveData<S> toRemote) {
super.removeSource(toRemote);
if (toRemote instanceof ActionLiveData) {
removeActionSource(toRemote);
}
}
protected <S> void removeActionSource(@NonNull LiveData<S> toRemote) {
ActionSource<?> source = mHandlers.remove(toRemote);
if (source != null) {
source.unplug();
}
}
public static class ActionSource<T> implements ActionHandler {
ActionLiveData<T> actionLiveData;
ActionObserver<T> actionObserver;
public ActionSource(ActionLiveData<T> actionLiveData, ActionObserver<T> actionObserver) {
this.actionLiveData = actionLiveData;
this.actionObserver = actionObserver;
}
void plug() {
actionLiveData.observeForever(actionObserver);
}
void unplug() {
actionLiveData.removeObserver(actionObserver);
}
@Override
public void onAction(int id, Object... args) {
actionObserver.onAction(id, args);
}
}
}
定義ActionTransformations修改Transformations的邏輯凳兵,以實(shí)現(xiàn)action事件的傳遞:
import android.arch.core.util.Function;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.Observer;
import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
/**
* Created by hubert on 2017/12/7.
* <p>
* 用于ActionLiveData的轉(zhuǎn)換,實(shí)現(xiàn)Action的傳遞
*/
public class ActionTransformations {
@MainThread
public static <X, Y> ActionLiveData<Y> map(@NonNull ActionLiveData<X> source,
@NonNull final Function<X, Y> func) {
final ActionLiveData<Y> result = new ActionLiveData<>();
result.addSource(source, new ActionObserver<X>() {
@Override
public void onChanged(@Nullable X x) {
result.setValue(func.apply(x));
}
@Override
public void onAction(int id, Object... args) {
result.setAction(id, args);
}
});
return result;
}
@MainThread
public static <X, Y> ActionLiveData<Y> switchMap(@NonNull LiveData<X> trigger,
@NonNull final Function<X, ActionLiveData<Y>> func) {
final ActionLiveData<Y> result = new ActionLiveData<>();
result.addSource(trigger, new Observer<X>() {
ActionLiveData<Y> mSource;
@Override
public void onChanged(@Nullable X x) {
ActionLiveData<Y> newLiveData = func.apply(x);
if (mSource == newLiveData) {
return;
}
if (mSource != null) {
result.removeSource(mSource);
}
mSource = newLiveData;
if (mSource != null) {
result.addSource(mSource, new ActionObserver<Y>() {
@Override
public void onAction(int id, Object... args) {
result.setAction(id, args);
}
@Override
public void onChanged(@Nullable Y y) {
result.setValue(y);
}
});
}
}
});
return result;
}
}
使用時也沒有多大的改變菱魔,只要把LiveData替換成ActionLiveData即可留荔。開始盡情的傳遞事件吧~ ??
這個擴(kuò)展是本人根據(jù)需求獨(dú)創(chuàng)的,如果覺得好不要吝惜你的“喜歡”哦。 當(dāng)然由于水平有限聚蝶,如果入不了你的眼杰妓,那肯定是比我厲害的大牛,有更好的建議或者思路可以提點(diǎn)我一下??碘勉,讓我也學(xué)習(xí)學(xué)習(xí)~