Android Jetpack架構組件(四)一文帶你瞭解LiveData(使用篇)

本文首發於微信公衆號「後廠村碼農」

前言

在2017年前後,RxJava一直很火,我在Android進階三部曲第一部《Android進階之光》中就介紹了RxJava的使用和原理。谷歌推出的LiveData和RxJava類似,也是基於觀察者,你可以認爲LiveData是輕量級的RxJava。起初LiveData並不被看好,隨着谷歌的大力推廣,LiveData也慢慢的進入了大家的視野。一般來說,LiveData很少單獨使用,它更多的和Android Jetpack的其他組件搭配使用,比如和ViewModel。這篇文章就來介紹LiveData的使用。

1.什麼是LiveData

LiveData如同它的名字一樣,是一個可觀察的數據持有者,和常規的observable不同,LiveData是具有生命週期感知的,這意味着它能夠在Activity、Fragment、Service中正確的處理生命週期。
mv4Y9I.png
LiveData的數據源一般是ViewModel,也可以是其它可以更新LiveData的組件。當數據更新後,LiveData 就會通知它的所有觀察者,比如Activiy。與RxJava的方法不同的是,LiveData並不是通知所有觀察者,它 只會通知處於Active狀態的觀察者,如果一個觀察者處於Paused或Destroyed狀態,它將不會收到通知。
這對於Activiy和Service特別有用,因爲它們可以安全地觀察LiveData對象而不用擔心內存泄漏的問題。開發者也不需要在onPause或onDestroy方法中解除對LiveData的訂閱。還有一點需要注意的是一旦觀察者重新恢復Resumed狀態,它將會重新收到LiveData的最新數據。

1.LiveData的基本用法

LiveData是一個抽象類,它的最簡單的實現類爲MutableLiveData,這裏舉個最簡單的例子。

public class MainActivity extends AppCompatActivity {
   private static final String TAG="MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MutableLiveData<String> mutableLiveData  = new MutableLiveData<>();
        mutableLiveData.observe(this, new Observer<String>() {//1
            @Override
            public void onChanged(@Nullable final String s) {
                Log.d(TAG, "onChanged:"+s);
            }
        });
        mutableLiveData.postValue("Android進階三部曲");//2
    }
}

註釋1處的observe方法有兩個參數分別是LifecycleOwner和 Observer<T> ,第一個參數就是MainActivity本身,第二個參數新建了一個Observer<String>,在onChanged方法中得到回調。註釋處的postValue方法會在主線程中更新數據,這樣就會得到打印的結果。
D/MainActivity: onChanged:Android進階三部曲

在大多數情況下,LiveData的observe方法會放在onCreate方法中,如果放在onResume方法中,會出現多次調用的問題。除了MutableLiveData的postValue方法,還可以使用setValue方法,它們之前的區別是,setValue方法必須在主線程使用,如果是在工作線程中更新LiveData,則可以使用postValue方法。

2.更改LiveData中的數據

如果我們想要在LiveData對象分發給觀察者之前對其中存儲的值進行更改,可以使用Transformations.map()和Transformations.switchMap(),下面通過簡單的例子來講解它們。

2.1 Transformations.map()

如果想要在LiveData對象分發給觀察者之前對其中存儲的值進行更改,可以使用Transformations.map()。

public class MainActivity extends AppCompatActivity {
   private static final String TAG="MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MutableLiveData<String> mutableLiveData  = new MutableLiveData<>();
        mutableLiveData.observe(this, new Observer<String>() {
            @Override
            public void onChanged(@Nullable final String s) {
                Log.d(TAG, "onChanged1:"+s);
            }
        });
        LiveData transformedLiveData =Transformations.map(mutableLiveData, new Function<String, Object>() {
            @Override
            public Object apply(String name) {
               return name + "+Android進階解密";
            }
        });
        transformedLiveData.observe(this, new Observer() {
            @Override
            public void onChanged(@Nullable Object o) {
                Log.d(TAG, "onChanged2:"+o.toString());
            }
        });
        mutableLiveData.postValue("Android進階之光");
    }
}

通過Transformations.map(),在mutableLiveData的基礎上又加上了字符串"+Android進階解密"。
打印結果爲:
D/MainActivity: onChanged1:Android進階之光
D/MainActivity: onChanged2:Android進階之光+Android進階解密

2.2 Transformations.switchMap()

如果想要手動控制監聽其中一個的數據變化,並能根據需要隨時切換監聽,這時可以使用Transformations.switchMap(),它和Transformations.map()使用方式類似,只不過switchMap()必須返回一個LiveData對象。

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    MutableLiveData<String> mutableLiveData1;
    MutableLiveData<String> mutableLiveData2;
    MutableLiveData<Boolean> liveDataSwitch;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mutableLiveData1 = new MutableLiveData<>();
        mutableLiveData2 = new MutableLiveData<>();
        liveDataSwitch = new MutableLiveData<Boolean>();//1

        LiveData transformedLiveData= Transformations.switchMap(liveDataSwitch, new Function<Boolean, LiveData<String>>() {
            @Override
            public LiveData<String> apply(Boolean input) {
                if (input) {
                    return mutableLiveData1;
                } else {
                    return mutableLiveData2;
               }
            }
        });

        transformedLiveData.observe(this, new Observer<String>() {
            @Override
            public void onChanged(@Nullable final String s) {
                Log.d(TAG, "onChanged:" + s);
            }
        });
        liveDataSwitch.postValue(false);//2
        mutableLiveData1.postValue("Android進階之光");
        mutableLiveData2.postValue("Android進階解密");
    }
}

註釋1處新建一個MutableLiveData<Boolean>()來控制切換並賦值給liveDataSwitch,當liveDataSwitch的值爲true時返回mutableLiveData1,否則返回mutableLiveData2。註釋2處將liveDataSwitch的值更新爲false,這樣輸出的結果爲"Android進階解密",達到了切換監聽的目的。

3 合併多個LiveData數據源

MediatorLiveData繼承自mutableLiveData,它可以將多個LiveData數據源集合起來,可以達到一個組件監聽多個LiveData數據變化的目的。

public class MainActivity extends AppCompatActivity {
   private static final String TAG="MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MutableLiveData<String> mutableLiveData1  = new MutableLiveData<>();
        MutableLiveData<String> mutableLiveData2  = new MutableLiveData<>();
        MediatorLiveData liveDataMerger = new MediatorLiveData<String>();
        liveDataMerger.addSource(mutableLiveData1, new Observer() {
            @Override
            public void onChanged(@Nullable Object o) {
                Log.d(TAG, "onChanged1:"+o.toString());
            }
        });

        liveDataMerger.addSource(mutableLiveData2, new Observer() {
            @Override
            public void onChanged(@Nullable Object o) {
                Log.d(TAG, "onChanged2:"+o.toString());
            }
        });
        liveDataMerger.observe(this, new Observer() {
            @Override
            public void onChanged(@Nullable Object o) {
                Log.d(TAG, "onChanged:"+o.toString());
            }
        });
        mutableLiveData1.postValue("Android進階之光");
    }
}

爲了更直觀的舉例,將LiveData和MediatorLiveData放到了同一個Activity中。通過MediatorLiveData的addSource將兩個MutableLiveData合併到一起,這樣當任何一個MutableLiveData數據發生變化時,MediatorLiveData都可以感知到。

打印的結果爲:
D/MainActivity: onChanged1:Android進階之光

4 拓展LiveData對象

如果觀察者的生命週期處於STARTED或RESUMED狀態,LiveData會將觀察者視爲處於Active狀態 。關於如何擴展LiveData,官網的例子是比較簡潔的,如下所示。

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);
    }
}

上面的代碼是一個觀察股票變動的一個例子,對LiveData進行了拓展,實現了LiveData的兩個空方法onActive和onInactive。當Active狀態的觀察者的數量從0變爲1時會調用onActive方法,通俗來講,就是當LiveData對象具有Active狀態的觀察者時調用onActive方法,應該在onActive方法中開始觀察股票價格的更新。當LiveData對象沒有任何Active狀態的觀察者時調用onInactive方法,在這個方法中,斷開與StockManager服務的連接。

在Fragment中使用StockLiveData,如下所示。

public class MyFragment extends Fragment {
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        StockLiveData.get(symbol).observe(this, price -> {
            // Update the UI.
        });
    }
}

總結

這篇文章主要介紹了什麼是LiveData,以及LiveData的使用方法,這裏沒有介紹LiveData和ViewModel的結合使用,以及LiveData的原理,這些會在後面的文章進行介紹。

更多的內容請關注我的獨立博客的知識體系:
http://liuwangshu.cn/system/


這裏不僅分享大前端、Android、Java等技術,還有程序員成長類文章。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章