最近研究了一下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()
當 LiveData 有一個處于活動狀態(tài)的觀察者時該方法被調(diào)用,這意味著需要開始從設(shè)備觀察位置更新。
- onInactive()
當 LiveData 沒有任何處于活動狀態(tài)的觀察者時該方法被調(diào)用。由于沒有觀察者在監(jiān)聽,所以沒有理由保持與 LocationManager 的連接。這是非常重要的,因為保持連接會顯著消耗電量并且沒有任何好處。
- setValue()
調(diào)用該方法更新 LiveData 實例的值,并將此變更通知給處于活動狀態(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)點:
沒有內(nèi)存泄漏:因為 Observer 被綁定到它們自己的 Lifecycle 對象上,所以,當它們的 Lifecycle 被銷毀時,它們能自動的被清理。
不會因為 activity 停止而崩潰:如果 Observer 的 Lifecycle 處于閑置狀態(tài)(例如:activity 在后臺時),它們不會收到變更事件。
始終保持數(shù)據(jù)最新:如果 Lifecycle 重新啟動(例如:activity 從后臺返回到啟動狀態(tài))將會收到最新的位置數(shù)據(jù)(除非還沒有)。
正確處理配置更改:如果 activity 或 fragment 由于配置更改(如:設(shè)備旋轉(zhuǎn))重新創(chuàng)建,將會立即收到最新的有效位置數(shù)據(jù)。
資源共享:可以只保留一個 MyLocationListener 實例,只連接系統(tǒng)服務(wù)一次,并且能夠正確的支持應(yīng)用程序中的所有觀察者。
不再手動管理生命周期你可能已經(jīng)注意到,fragment 只是在需要的時候觀察數(shù)據(jù),不用擔心被停止或者在停止之后啟動觀察。由于 fragment 在觀察數(shù)據(jù)時提供了其 Lifecycle,所以 LiveData 會自動管理這一切。
問題
看了以上的介紹,發(fā)現(xiàn)LiveData還是非常好用的,等同于以前用rxLifecycle來管理生命周期,但是在實際使用的時候就發(fā)現(xiàn)問題了,LiveData只能傳遞一個值,之前我們用Retrofit+OkHttp+rxJava等構(gòu)建MVP模式的應(yīng)用時,網(wǎng)絡(luò)數(shù)據(jù)請求經(jīng)常會有多種結(jié)果:(1)正常返回數(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ò)異常等等那???啰嗦了這么半天,終于引出今天的話題——擴展LiveData 以滿足需求。
擴展
先來分析一下LiveData,當添加了觀察者,一旦調(diào)用setValue方法,觀察者的onChanged方法就會接受到新的值。傳遞的值是通過LiveData<T>泛型定義。
既然是要區(qū)分類型,一開始的思路是將泛型定義成自定義的ActionEntity<T>,有點類似網(wǎng)絡(luò)接口返回,id區(qū)分類型,extra附帶額外數(shù)據(jù),original是原始的value數(shù)據(jù),即將真實數(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方法實現(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方法實現(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ū)別原方法。
這樣修改的話直接使用的話是能達到我的目的,但是通常情況下LiveData會通過Transformations進行轉(zhuǎn)換,這時候泛型將很難定義,而且無法申明我們定義的類,因為Transformations的switchMap方法返回的必須是LiveData<T>,泛型只能定義成LiveData<ActionEntity<T>>,雖然我的定義的ActionLiveData2<T>也是繼承自LiveData<ActionEntity<T>>,但是并不相等?。。?!
于是自己都寫不下去了?? 并且這樣的命名也非常的讓我不爽,于是廢棄了這種方式。
接著我又有了一個想法??,直接讓LiveData傳遞Action,就像傳遞Value一樣地傳遞:通過setAction設(shè)置事件,并且在Observer中onAction方法中接受事件作出處理。這個可以有!仿照value是怎么傳遞的不就行了嘛!??
然后我仔細分析了LiveData的源碼,了解了其中是如何傳遞Value的,但是其中處理value的方法基本都是private的,子類無法使用。因此,我只能按照同樣的邏輯來實現(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)該完美!?? 各種斷點找原因,到底為什么沒有傳遞過來。。。
最終被我發(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進行轉(zhuǎn)換,或者說傳遞,即讓一個LiveData(view層中獲得的那個,我們簡稱小v)觀察另一個LiveData(M層生成的小m),請求數(shù)據(jù)只會改變小m的value,switchMap方法內(nèi)部其實就是給小m設(shè)置一個Observer,當小m的value改變時會調(diào)用該Observer的onChanged方法,在該方法中調(diào)用小v的setValue,這樣View層的Observer的onChanged方法就可以改變界面。
其中只處理了value的傳遞,并且返回的對象是方法內(nèi)部new的這個final MediatorLiveData<Y> result = new MediatorLiveData<>();,我們自己新添加的action當然不會被傳遞啦。
??既然這樣,那我們就自己傳遞吧。還是仿照MediatorLiveData中傳遞方式,新增一個ActionSource類:
/**
* Created by hubert on 2017/12/6.
* <p>
* LiveData本身只能有一種泛型的數(shù)據(jù),在(接口)數(shù)據(jù)返回時只能設(shè)置有值或者null來判斷,
* 無法傳遞其他信息,如需要提示網(wǎng)絡(luò),數(shù)據(jù)錯誤等情況,為每一種情況定義一個LiveData又太過于繁瑣。
* 基于以上考慮對LiveData進行擴展,使其支持傳遞自定義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的邏輯,以實現(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)換,實現(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即可。開始盡情的傳遞事件吧~ ??
這個擴展是本人根據(jù)需求獨創(chuàng)的,如果覺得好不要吝惜你的“喜歡”哦。 當然由于水平有限,如果入不了你的眼,那肯定是比我厲害的大牛,有更好的建議或者思路可以提點我一下??,讓我也學(xué)習(xí)學(xué)習(xí)~