Android LiveData 使用詳解
說在前面
本次推出 Android Architecture Components 系列文章,目前寫好了四篇,主要是關於 lifecycle,livedata 的使用和原始碼分析,其餘的 Navigation, Paging library,Room,WorkMannager 等春節結束之後會更新,歡迎關注我的公眾號,有更新的話會第一時間會在公眾號上面通知。
github sample 地址: ArchiteComponentsSample
Android 技術人,一位不羈的碼農。

Android 技術人
前言
在上一篇部落格中,我們講解了 lifecycle 的使用及優點。這篇部落格讓我們一起來了解一下 LiveData 是怎樣使用的?
為什麼要引進 LiveData
LiveData 是一個可以被觀察的資料持有類,它可以感知 Activity、Fragment或Service 等元件的生命週期。簡單來說,他主要有一下優點。
- 它可以做到在元件處於啟用狀態的時候才會回撥相應的方法,從而重新整理相應的 UI。
- 不用擔心發生記憶體洩漏
- 當 config 導致 activity 重新建立的時候,不需要手動取處理資料的儲存和恢復。它已經幫我們封裝好了。
- 當 Actiivty 不是處於啟用狀態的時候,如果你想 livedata setValue 之後立即回撥 obsever 的 onChange 方法,而不是等到 Activity 處於啟用狀態的時候才回調 obsever 的 onChange 方法,你可以使用 observeForever 方法,但是你必須在 onDestroy 的時候 removeObserver。
回想一下,在你的專案中,是不是經常會碰到這樣的問題,當網路請求結果回來的時候,你經常需要判斷 Activity 或者 Fragment 是否已經 Destroy, 如果不是 destroy,才更新 UI。而當你如果使用 Livedata 的話,因為它是在 Activity 處於 onStart 或者 onResume 的狀態時,他才會進行相應的回撥,因而可以很好得處理這個問題,不必謝一大堆的 activity.isDestroyed()。接下來,讓我們一起來看一下 LiveData 的使用
LiveData 使用
基本使用
- 引入相關的依賴包
// ViewModel and LiveData implementation "android.arch.lifecycle:extensions:1.1.0" // alternatively, just ViewModel implementation "android.arch.lifecycle:viewmodel:1.1.0" // alternatively, just LiveData implementation "android.arch.lifecycle:livedata:1.1.0"
- 在程式碼中使用
LiveData 是一個抽象類,它的實現子類有 MutableLiveData ,MediatorLiveData。在實際使用中,用得比較多的是 MutableLiveData。他常常結合 ViewModel 一起使用。下面,讓我們一起來看一下怎樣使用它?
首先,我們先寫一個類繼承我們的 ViewModel,裡面持有 mNameEvent。
public class TestViewModel extends ViewModel { private MutableLiveData<String> mNameEvent = new MutableLiveData<>(); public MutableLiveData<String> getNameEvent() { return mNameEvent; } }
接著,我們在 Activity 中建立 ViewModel,並監聽 ViewModel 裡面 mNameEvent 資料的變化,當資料改變的時候,我們列印相應的 log,並設定給 textView,顯示在介面上。這樣我們就完成了對 mNameEvent 資料來源的觀察。
mTestViewModel = ViewModelProviders.of(this).get(TestViewModel.class); MutableLiveData<String> nameEvent = mTestViewModel.getNameEvent(); nameEvent.observe(this, new Observer<String>() { @Override public void onChanged(@Nullable String s) { Log.i(TAG, "onChanged: s = " + s); mTvName.setText(s); } });
最後當我們資料來源改變的時候,我們需要呼叫 livedata 的 setValue 或者 postvalue 方法。他們之間的區別是, 呼叫 setValue 方法,Observer 的 onChanged 方法會在呼叫 serValue 方法的執行緒回撥。而
postvalue 方法,Observer 的 onChanged 方法將會在主執行緒回撥。
mTestViewModel.getNameEvent().setValue(name);
可能部分同學有這樣的疑問了, 我們的 ViewModel 是通過 ViewModelProviders.of(this).get(TestViewModel.class); 方法創建出來的,如果我們要攜帶引數,怎麼辦?
其實,官方也替我們考慮好了,同樣是呼叫 ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) 方法,只不過,需要多傳遞一個 factory 引數。
Factory 是一個介面,它只有一個 create 方法。
public interface Factory { /** * Creates a new instance of the given {@code Class}. * <p> * * @param modelClass a {@code Class} whose instance is requested * @param <T>The type parameter for the ViewModel. * @return a newly created ViewModel */ @NonNull <T extends ViewModel> T create(@NonNull Class<T> modelClass); }
在實際當中,我們的做法是:實現 Factory 介面,重寫 create 方法,在create 方法裡面呼叫相應的建構函式,返回相應的例項。
public class TestViewModel extends ViewModel { private final String mKey; private MutableLiveData<String> mNameEvent = new MutableLiveData<>(); public MutableLiveData<String> getNameEvent() { return mNameEvent; } public TestViewModel(String key) { mKey = key; } public static class Factory implements ViewModelProvider.Factory { private String mKey; public Factory(String key) { mKey = key; } @Override public <T extends ViewModel> T create(Class<T> modelClass) { return (T) new TestViewModel(mKey); } } public String getKey() { return mKey; } }
ViewModelProviders.of(this, new TestViewModel.Factory(mkey)).get(TestViewModel.class)
自定義 Livedata
Livedata 主要有幾個方法
- observe
- onActive
- onInactive
- observeForever
void observe (LifecycleOwner owner, Observer<T> observer)
Adds the given observer to the observers list within the lifespan of the given owner. The events are dispatched on the main thread. If LiveData already has data set, it will be delivered to the observer.
void onActive ()
Called when the number of active observers change to 1 from 0.This callback can be used to know that this LiveData is being used thus should be kept up to date.
當回撥該方法的時候,表示該 liveData 正在背使用,因此應該保持最新
void onInactive ()
Called when the number of active observers change from 1 to 0.This does not mean that there are no observers left, there may still be observers but their lifecycle states aren't STARTED or RESUMED (like an Activity in the back stack).You can check if there are observers via hasObservers().
當該方法回撥時,表示他所有的 obervers 沒有一個狀態處理 STARTED 或者 RESUMED,注意,這不代表沒有 observers。
Void observeForever
跟 observe 方法不太一樣的是,它在 Activity 處於 onPause ,onStop, onDestroy 的時候,都可以回撥 obsever 的 onChange 方法,但是有一點需要注意的是,我們必須手動 remove obsever,否則會發生記憶體洩漏。
這裡我們以觀察網路狀態變化為例子講解
- 首先我們自定義一個 Class NetworkLiveData,繼承 LiveData,重寫它的 onActive 方法和 onInactive 方法
- 在 onActive 方法中,我們註冊監聽網路變化的廣播,即ConnectivityManager.CONNECTIVITY_ACTION。在 onInactive 方法的時候,我們登出廣播。
public class NetworkLiveData extends LiveData<NetworkInfo> { private final Context mContext; static NetworkLiveData mNetworkLiveData; private NetworkReceiver mNetworkReceiver; private final IntentFilter mIntentFilter; private static final String TAG = "NetworkLiveData"; public NetworkLiveData(Context context) { mContext = context.getApplicationContext(); mNetworkReceiver = new NetworkReceiver(); mIntentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); } public static NetworkLiveData getInstance(Context context) { if (mNetworkLiveData == null) { mNetworkLiveData = new NetworkLiveData(context); } return mNetworkLiveData; } @Override protected void onActive() { super.onActive(); Log.d(TAG, "onActive:"); mContext.registerReceiver(mNetworkReceiver, mIntentFilter); } @Override protected void onInactive() { super.onInactive(); Log.d(TAG, "onInactive: "); mContext.unregisterReceiver(mNetworkReceiver); } private static class NetworkReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { ConnectivityManager manager = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetwork = manager.getActiveNetworkInfo(); getInstance(context).setValue(activeNetwork); } } }
這樣,當我們想監聽網路變化的時候,我們只需要呼叫相應的 observe 方法即可,方便又快捷。
NetworkLiveData.getInstance(this).observe(this, new Observer<NetworkInfo>() { @Override public void onChanged(@Nullable NetworkInfo networkInfo) { Log.d(TAG, "onChanged: networkInfo=" +networkInfo); } });
https://www.jianshu.com/p/4b7945475a6f
共享資料
Fragment Activity 之間共享資料
我們回過頭來再來看一下 ViewModelProvider 的 of 方法,他主要有四個方法,分別是
- ViewModelProvider of(@NonNull Fragment fragment)
- ViewModelProvider of(@NonNull FragmentActivity activity)
- ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory)
- ViewModelProvider of(@NonNull FragmentActivity activity, @Nullable Factory factory)
1,2 方法之間的主要區別是傳入 Fragment 或者 FragmentActivity。而我們知道,通過 ViewModel of 方法建立的 ViewModel 例項, 對於同一個 fragment 或者 fragmentActivity 例項,ViewModel 例項是相同的,因而我們可以利用該特點,在 Fragment 中建立 ViewModel 的時候,傳入的是 Fragment 所依附的 Activity。因而他們的 ViewModel 例項是相同的,從而可以做到共享資料。
// LiveDataSampleActivity(TestFragment 依賴的 Activity) mTestViewModel = ViewModelProviders.of(this, new TestViewModel.Factory(mkey)).get(TestViewModel.class); MutableLiveData<String> nameEvent = mTestViewModel.getNameEvent(); nameEvent.observe(this, new Observer<String>() { @Override public void onChanged(@Nullable String s) { Log.i(TAG, "onChanged: s = " + s); mTvName.setText(s); } }); // TestFragment 中 mViewModel = ViewModelProviders.of(mActivity).get(TestViewModel.class); mViewModel.getNameEvent().observe(this, new Observer<String>() { @Override public void onChanged(@Nullable String s) { Log.d(TAG, "onChanged: s =" + s + " mViewModel.getKey() =" + mViewModel.getKey()); mTvName.setText(s); boolean result = mViewModel == ((LiveDataSampleActivity) mListener).mTestViewModel; Log.d(TAG, "onChanged: s result =" + result); } });
這樣,LiveDataSampleActivity 和 TestFragment 中的 ViewModel 是同一個例項。即 Activity 和 Fragment 共享資料。
全域性共享資料
說到全域性共享資料,我們想一下我們的應用全景,比如說我的賬戶資料,這個對於整個 App 來說,肯定是全域性共享的。有時候,當我們的資料變化的時候,我們需要通知我們相應的介面,重新整理 UI。如果用傳統的方式來實現,那麼我們一般才採取觀察者的方式來實現,這樣,當我們需要觀察資料的時候,我們需要新增 observer,在介面銷燬的時候,我們需要移除 observer。
但是,如果我們用 LiveData 來實現的話,它內部邏輯都幫我們封裝好了,我們只需要保證 AccountLiveData 是單例的就ok,在需要觀察的地方呼叫 observer 方法即可。也不需要手動移除 observer,不會發生記憶體洩漏,方便快捷。
這裡 AccountLiveData 的實現就不貼出來了,可以參考上面的 NetworkLiveData 實現
小結
這裡說一點關於 LiveData 與 ViewModel 的應用場景吧,我儘量說得通俗一點,不要說得那麼官方,這樣對新手很難理解。覺得不錯的,請點個贊,讓我們看到你們的歡呼聲。你們的支援就是我寫作的最大動力。
- LiveData 內部已經實現了觀察者模式,如果你的資料要同時通知幾個介面,可以採取這種方式
- 我們知道 LiveData 資料變化的時候,會回撥 Observer 的 onChange 方法,但是回撥的前提是 lifecycleOwner(即所依附的 Activity 或者 Fragment) 處於 started 或者 resumed 狀態,它才會回撥,否則,必須等到 lifecycleOwner 切換到前臺的時候,才回調。因此,這對效能方面確實是一個不小的提升。但是,對於你想做一些類似與在後臺工作的(黑科技), liveData 就不太適合了,你可以使用 observeForever 方法,或者自己實現觀察者模式去吧。
Lifecycle,LiveData, ViewModel 的基本使用到此已經講解完畢,想了解他們的實現原理的話可以閱讀這兩篇文章。