Architecture Components之LiveData的擴展

最近研究了一下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 停止而崩潰:如果 ObserverLifecycle 處于閑置狀態(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ù)雜的具體的情況。

final-architecture.png

上圖是官方提供的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í)~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容