LiveData使用

一、前言:

1. 簡介:

1、LiveData的簡介

LiveData是一種類,持有可被觀察的數(shù)據(jù)。
LiveData是一種可感知生命周期的組件,意味著該組件重視其他app組件的生命周期,如Activity、Fragment、Service
該組件能確保,僅僅在Activity\Fragment\Service等組件都處于活躍的生命周期狀態(tài)的時候,才去更新app組件。

2、LiveData只有當觀察者的生命周期處于活躍狀態(tài)時才會去通知觀察者。

實現(xiàn)了Observer類的觀察者,可以注冊監(jiān)聽LiveData
活躍狀態(tài)就是指處于STARTED或者RESUMED狀態(tài)
處于非活躍的觀察者,LiveData不會去通知這些觀察者

3、可以注冊一種觀察者, 該觀察者與LifecycleOwner對象(如:Activity、Fragment)相關(guān)聯(lián)。

在對應(yīng)的Lifecycle Object處于DESTORYED狀態(tài)時,會自動解除LiveData和該觀察者的注冊關(guān)系

4、在Activity、Fragment中這種自動解除注冊的特性非常有用

Activity、Fragment不用擔心會出現(xiàn)內(nèi)存泄露
在Activity、Fragment銷毀時,LiveData會自動解除其注冊關(guān)系

2. 優(yōu)勢:

5、LiveData能確保UI和數(shù)據(jù)狀態(tài)相符

因為是觀察者模式,LiveData會在生命周期狀態(tài)改變時,通知觀察者
可以在觀察者對象中進行UI的更新操作

6、LiveData沒有內(nèi)存泄露

觀察者和Lifecycle對象綁定,能在銷毀時自動解除注冊

7、LiveData不會給已經(jīng)停止的Activity發(fā)送事件

如果觀察者處于非活躍狀態(tài),LiveData不會再發(fā)送任何事件給這些Observer對象

8、LiveData能確保不再需要手工對生命周期進行處理

UI組件僅僅需要對相關(guān)數(shù)據(jù)進行觀察
LiveData自動處理生命周期狀態(tài)改變后,需要處理的代碼。

9、LiveData能保證數(shù)據(jù)最新

一個非活躍的組件進入到活躍狀態(tài)后,會立即獲取到最新的數(shù)據(jù)
不用擔心數(shù)據(jù)問題

10、LiveData在橫豎屏切換等Configuration改變時,也能保證獲取到最新數(shù)據(jù)

例如Acitivty、Fragment因為屏幕選裝導(dǎo)致重建, 能立即接收到最新的數(shù)據(jù)

11、LiveData能資源共享

如果將LiveData對象擴充,用單例模式將系統(tǒng)服務(wù)進行包裹。這些服務(wù)就可以在app中共享。
只需要LiveData和系統(tǒng)服務(wù)connect,其他觀察者只需要監(jiān)視LiveData就能獲取到這些資源

二、使用LiveData

1、LiveData與MutableLiveData區(qū)別

LiveData與MutableLiveData的其實在概念上是一模一樣的.唯一幾個的區(qū)別如下:

  1. MutableLiveData的父類是LiveData
  2. LiveData在實體類里可以通知指定某個字段的數(shù)據(jù)更新.
  3. MutableLiveData則是完全是整個實體類或者數(shù)據(jù)類型變化后才通知.不會細節(jié)到某個字段

2、LiveData有幾種使用方式:

  1. 使用LiveData對象
  2. 繼承LiveData類

3、為什么將LiveData放置到ViewModel中,而不放到activity或者fragment中?

  1. 避免fragment和activity的代碼臃腫
  2. 將LiveData和特定的activity/fragment解耦,能夠在configuration改變的時候,LiveData依然存活。

4、在App組件的哪個生命周期適合觀察LiveData對象?為什么?

  1. app組件的onCreate()方法
  2. 不適合在onResume()等方法中,可能會調(diào)用多次
  3. 能確保組件能盡可能快的展示出數(shù)據(jù)。只要app組件處于啟動狀態(tài)(STARTED)就會立即接收到LiveData對象中的數(shù)據(jù)—前提是已經(jīng)監(jiān)聽了LiveData

5、ViewModelProviders為什么找不到?

引用的版本太老了,需要新的Lifecyle擴展庫(目前可以用的最新版)
//viewMouble使用
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'

6、創(chuàng)建LiveData實例

Android文檔中建議LiveData配合ViewModel使用更加哦,其實呢,你也可以不使用ViewModel,但是一定要做到LiveData中保存的數(shù)據(jù)和組件分離,至于原因,前面我們已經(jīng)提到過了。下面是在ViewModel中創(chuàng)建LiveData實例的例子:

public class NameViewModel extends ViewModel{
    // Create a LiveData with a String
    private MutableLiveData<String> mCurrentName;
    // Create a LiveData with a String list
    private MutableLiveData<List<String>> mNameListData;

    public MutableLiveData<String> getCurrentName() {
        if (mCurrentName == null) {
            mCurrentName = new MutableLiveData<>();
        }
        return mCurrentName;
    }

    public MutableLiveData<List<String>> getNameList(){
        if (mNameListData == null) {
            mNameListData = new MutableLiveData<>();
        }
        return mNameListData;
    }
}

在NameViewModel中創(chuàng)建了兩個MutableLiveData(MutableLiveData是LiveData的子類)實例,分別存儲當前姓名、姓名列表;兩個實例通過NameViewModel中的getter方法得到。

7、創(chuàng)建Observer對象,添加觀察者

public class LiveDataFragment extends Fragment {
    private static final String TAG = "LiveDataFragment";
    private NameViewModel mNameViewModel;
    @BindView(R.id.tv_name)
    TextView mTvName;

    public static LiveDataFragment getInstance(){
        return new LiveDataFragment();
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mNameViewModel = ViewModelProviders.of(this).get(NameViewModel.class);
        // 訂閱LiveData中當前Name數(shù)據(jù)變化,以lambda形式定義Observer
      mNameViewModel.getCurrentName().observe(this, new Observer<String>() {
            @Override
            public void onChanged(String name) {
                mTvName.setText(name);
                Log.d(TAG, "currentName: " + name);
            }
        });
       // 訂閱LiveData中Name列表數(shù)據(jù)變化,以lambda形式定義Observer
      mNameViewModel.getNameList().observe(this, new Observer<List<String>>() {
            @Override
            public void onChanged(List<String> nameList) {
                for (String item : nameList) {
                    Log.d(TAG, "name: " + item);
                }
            }
        });
    }


    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.layout_livedata, container, false);
        ButterKnife.bind(this, view);
        return view;
    }

}

在onCreate()方法中通過LiveData.observe()方法添加觀察者,當數(shù)據(jù)變化時會通過回調(diào)方法通知觀察者,在lambda表達式中更新當前姓名和打印姓名列表。

8、更新LiveData中的數(shù)據(jù)

在上面我們已經(jīng)訂閱了LiveData數(shù)據(jù)變化,現(xiàn)在我們看下如果LiveData數(shù)據(jù)變化時,上面的lambda表達式中是否會受到更新的通知。我們在LiveDataFragment中增加兩個按鈕來改變LiveData中的數(shù)據(jù)。

@OnClick({R.id.btn_change_name, R.id.btn_update_list})
void onClicked(View view){
    switch (view.getId()){
        case R.id.btn_change_name:
            mNameViewModel.getCurrentName().setValue("Jane");
            break;
        case R.id.btn_update_list:
            List<String> nameList = new ArrayList<>();
            for (int i = 0; i < 10; i++){
                nameList.add("Jane<" + i + ">");
            }
            mNameViewModel.getNameList().setValue(nameList);
            break;
    }
}

代碼很簡單,在兩個按鈕的點擊事件中通過LiveData.setValue()方法來改變LiveData中保存的數(shù)據(jù)。當點擊這兩個按鈕的時候,我們會發(fā)現(xiàn)在onCreate()方法中會收相應(yīng)到數(shù)據(jù)改變的回調(diào)。

9、繼承LiveData類

除了直接使用LiveDatad對象外,我們還可以通過集成LiveData類來定義適合特定需求的LiveData。下面繼承LiveData類的例子,驗證下LiveData的其中一個優(yōu)點——資源共享。

package com.hao.architecture;

import android.arch.lifecycle.LiveData;

import java.math.BigDecimal;

public class StockLiveData extends LiveData<BigDecimal> {
    private StockManager stockManager;

    public StockLiveData(String symbol) {
        stockManager = new StockManager(symbol);
    }

    private SimplePriceListener listener = new SimplePriceListener() {
        @Override
        public void onPriceChanged(BigDecimal price) {
            // 更新LiveData并且通知所有活躍的觀察者
            setValue(price);
        }
    };

    @Override
    protected void onActive() {
        // 具有活躍的觀察者時調(diào)用
        stockManager.requestPriceUpdates(listener);
    }

    @Override
    protected void onInactive() {
        // 沒有任何活躍的觀察者時調(diào)用
        stockManager.removeUpdates(listener);
    }
}
  • onActive(),此方法是當處于激活狀態(tài)的observer個數(shù)從0到1時,該方法會被調(diào)用。
  • onInactive() ,此方法是當處于激活狀態(tài)的observer個數(shù)從1變?yōu)?時,該方法會被調(diào)用。

10、改變LiveData數(shù)據(jù)

LiveData提供了兩種改變數(shù)據(jù)的方法:setValue()和postValue()。
區(qū)別是:

  • setValue()要在主線程中調(diào)用,
  • postValue()既可在主線程也可在子線程中調(diào)用。

我們先看setValue()方法的具體實現(xiàn):

@MainThread
protected void setValue(T value) {
    assertMainThread("setValue"); //判斷當前線程是否是主線程,不是主線程就拋出異常
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

再看下postValue()方法的具體實現(xiàn):

protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask) {
        return;
    }
    // 會在主線程中執(zhí)行  mPostValueRunnable中的內(nèi)容。
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable); 
}

private final Runnable mPostValueRunnable = new Runnable() {
    @Override
    public void run() {
        Object newValue;
        synchronized (mDataLock) {
            newValue = mPendingData;
            mPendingData = NOT_SET;
        }
        // 在主線程中調(diào)用setValue()方法
        setValue((T) newValue); 
    }
};

postValue()方法通過ArchTaskExecutor實現(xiàn)在主線程中執(zhí)行mPostValueRunnable對象中的內(nèi)容,而在mPostValueRunnable中最終會調(diào)用setValue()方法來實現(xiàn)改變LiveData存儲的數(shù)據(jù)。

11、添加觀察者

LiveData提供了兩種添加觀察者的方法:observeForever()、observe()。

  • observeForever()
@MainThread
public void observeForever(@NonNull Observer<T> observer) {
    observe(ALWAYS_ON, observer);
}

從方法的命名,我們也能對它的功能略知一二,通過observeForever()添加觀察者,觀察者會一直受到數(shù)據(jù)的變化回到,而不是在組件處于STARTED和RESUMED狀態(tài)下才會收到,因為這是LifecycleOwner對象就不再是組件了,而是ALWAYS_ON;另外通過該方法添加觀察者后,要手動調(diào)用removeObserver()方法來停止觀察者接收回調(diào)通知。observeForever()方法體很簡單,調(diào)用了observe()方法,傳入的一個參數(shù)是ALWAYS_ON常量,重點看下ALWAYS_ON常量是個啥東東。

private static final LifecycleOwner ALWAYS_ON = new LifecycleOwner() {

    private LifecycleRegistry mRegistry = init();

    private LifecycleRegistry init() {
        LifecycleRegistry registry = new LifecycleRegistry(this);
        registry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
        registry.handleLifecycleEvent(Lifecycle.Event.ON_START);
        registry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
        return registry;
    }

    @Override
    public Lifecycle getLifecycle() {
        return mRegistry;
    }
};

ALWAYS_ON是LifecycleOwner常量,在init方法中會初始化Lifecycle的生命周期狀態(tài),完了之后,就沒有改變過Lifecycle的生命周期狀態(tài)了,這也就是為什么通過observeForever()添加觀察者是,當數(shù)據(jù)改變時不管組件處于什么狀態(tài)都會收到回調(diào)的原因,除非手動將觀察者移除。

  • observe()
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    //將LifecycleOwner對象和Observer對象封裝成LifecycleBoundObserver對象。
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    // mObservers可以理解成一個類似Map的容器,putIfAbsent()方法是判斷容器中的observer(key)
    // 是否有已經(jīng)和wrapper(value)關(guān)聯(lián),如果已經(jīng)關(guān)聯(lián)則返回關(guān)聯(lián)值,否則關(guān)聯(lián)并返回wrapper。
    LifecycleBoundObserver existing = mObservers.putIfAbsent(observer, wrapper);
    if (existing != null && existing.owner != wrapper.owner) {
        throw new IllegalArgumentException("Cannot add the same observer"
                + " with different lifecycles");
    }
    if (existing != null) {
        return;
    }
    owner.getLifecycle().addObserver(wrapper); //條件LifecycleOwner的生命周期觀察者
}

該方法也比較簡單,主要邏輯都在注釋中說明了,就不再贅述了。


鏈接:http://m.itdecent.cn/p/2fa0aa513a32

?著作權(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ù)。

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