Android LiveData 使用詳解

說在前面

本次推出 Android Architecture Components 系列文章,目前寫好了四篇,主要是關於 lifecycle,livedata 的使用和源碼分析,其他的 Navigation, Paging library,Room,WorkMannager 等春節結束以後會更新,歡迎關注個人公衆號,有更新的話會第一時間會在公衆號上面通知。javascript

Android lifecycle 使用詳解java

Android LiveData 使用詳解android

Android lifecyle 源碼解剖git

Android livedata 源碼解剖github

github sample 地址: ArchiteComponentsSample網絡

Android 技術人,一位不羈的碼農。ide

Android 技術人


前言

在上一篇博客中,咱們講解了 lifecycle 的使用及優勢。這篇博客讓咱們一塊兒來了解一下 LiveData 是怎樣使用的?函數


爲何要引進 LiveData

LiveData 是一個能夠被觀察的數據持有類,它能夠感知 Activity、Fragment或Service 等組件的生命週期。簡單來講,他主要有一下優勢。源碼分析

  1. 它能夠作到在組件處於激活狀態的時候纔會回調相應的方法,從而刷新相應的 UI。
  2. 不用擔憂發生內存泄漏
  3. 當 config 致使 activity 從新建立的時候,不須要手動取處理數據的儲存和恢復。它已經幫咱們封裝好了。
  4. 當 Actiivty 不是處於激活狀態的時候,若是你想 livedata setValue 以後當即回調 obsever 的 onChange 方法,而不是等到 Activity 處於激活狀態的時候纔回調 obsever 的 onChange 方法,你可使用 observeForever 方法,可是你必須在 onDestroy 的時候 removeObserver。

回想一下,在你的項目中,是否是常常會碰到這樣的問題,當網絡請求結果回來的時候,你常常須要判斷 Activity 或者 Fragment 是否已經 Destroy, 若是不是 destroy,才更新 UI。而當你若是使用 Livedata 的話,由於它是在 Activity 處於 onStart 或者 onResume 的狀態時,他纔會進行相應的回調,於是能夠很好得處理這個問題,沒必要謝一大堆的 activity.isDestroyed()。接下來,讓咱們一塊兒來看一下 LiveData 的使用post


LiveData 使用

基本使用

  1. 引入相關的依賴包
// 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"
複製代碼
  1. 在代碼中使用

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 主要有幾個方法

  1. observe
  2. onActive
  3. onInactive
  4. observeForever

void observe (LifecycleOwner owner, Observer 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,不然會發生內存泄漏。

這裏咱們以觀察網絡狀態變化爲例子講解

  1. 首先咱們自定義一個 Class NetworkLiveData,繼承 LiveData,重寫它的 onActive 方法和 onInactive 方法
  2. 在 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);
    }
});

複製代碼

www.jianshu.com/p/4b7945475…

共享數據

Fragment Activity 之間共享數據

咱們回過頭來再來看一下 ViewModelProvider 的 of 方法,他主要有四個方法,分別是

  1. ViewModelProvider of(@NonNull Fragment fragment)
  2. ViewModelProvider of(@NonNull FragmentActivity activity)
  3. ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory)
  4. 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 的應用場景吧,我儘可能說得通俗一點,不要說得那麼官方,這樣對新手很難理解。以爲不錯的,請點個贊,讓咱們看到大家的歡呼聲。大家的支持就是我寫做的最大動力。

  1. LiveData 內部已經實現了觀察者模式,若是你的數據要同時通知幾個界面,能夠採起這種方式
  2. 咱們知道 LiveData 數據變化的時候,會回調 Observer 的 onChange 方法,可是回調的前提是 lifecycleOwner(即所依附的 Activity 或者 Fragment) 處於 started 或者 resumed 狀態,它纔會回調,不然,必須等到 lifecycleOwner 切換到前臺的時候,纔回調。所以,這對性能方面確實是一個不小的提高。可是,對於你想作一些相似與在後臺工做的(黑科技), liveData 就不太適合了,你可使用 observeForever 方法,或者本身實現觀察者模式去吧。

Lifecycle,LiveData, ViewModel 的基本使用到此已經講解完畢,想了解他們的實現原理的話能夠閱讀這兩篇文章。

Android lifecyle 源碼解剖

Android livedata 源碼解剖

github sample 地址: ArchiteComponentsSample

相關文章
相關標籤/搜索