Android架構(gòu)組件之LiveData

如果你看過了Android架構(gòu)組件之Lifecycle,可以立馬投入到LiveData組件的學(xué)習(xí)中,同樣的,LiveData也是Google I/O 大會(huì)上發(fā)布的架構(gòu)組件,ListData是一個(gè)可被觀察的數(shù)據(jù)持有類,為我們什么需要使用LiveData?主要有以下幾個(gè)有點(diǎn):
更多參考

一,保證數(shù)據(jù)與界面的實(shí)時(shí)更新

LiveData采用了觀察者模式設(shè)計(jì),其中LiveData是被觀察者,當(dāng)數(shù)據(jù)發(fā)生變化時(shí)會(huì)通知觀察者進(jìn)行數(shù)據(jù)更新。通過這點(diǎn),可以確保數(shù)據(jù)和界面的實(shí)時(shí)性。

二,有效避免內(nèi)存泄漏

這是因?yàn)?code>LiveData能夠感知到組件的生命周期,當(dāng)組件狀態(tài)處于DESTROYED狀態(tài)時(shí),觀察者對(duì)象會(huì)被remove。

三,Activity/Fragment銷毀掉時(shí)不會(huì)引起崩潰

這是因?yàn)榻M件處于非激活狀態(tài)時(shí),在界面不會(huì)收到來自LiveData的數(shù)據(jù)變化通知。這樣規(guī)避了很多因?yàn)轫撁驿N毀之后,修改UI導(dǎo)致的crash。

四,不需要手動(dòng)處理生命周期

LiveData能夠感知組件的生命周期,所以設(shè)置LiveData組件的生命周期狀態(tài)。

五,始終能夠保持最新數(shù)據(jù)

生命周期從非活躍狀態(tài)切換到活躍狀態(tài)的時(shí)候,能夠?qū)崟r(shí)的接收最新的數(shù)據(jù)。

六,能夠應(yīng)對(duì)配置更改

由于LiveData保存數(shù)據(jù)的時(shí)候,組件和數(shù)據(jù)是分離的,所以在配置更改(如橫豎屏切換等)的時(shí)候,即便組件被重新創(chuàng)建,因?yàn)閿?shù)據(jù)還保存在LiveData中,這樣也能夠做到實(shí)時(shí)的更新。

七,資源共享

單例模式擴(kuò)展LiveData對(duì)象并包裝成系統(tǒng)服務(wù),以便在應(yīng)用程序中進(jìn)行共享,需要該資源的只需要觀察LiveData即可。

LiveData的使用

相關(guān)Gradle配置參考

通常使用LiveData有三個(gè)步驟:
1,創(chuàng)建LiveData實(shí)例來保存數(shù)據(jù),常常是配合ViewModel一起工作;
2,定義一個(gè)Observer的觀察者對(duì)象,如果有數(shù)據(jù)更新會(huì)通過觀察者的onChanged()方法來同步到UI上面;
3,將觀察者Observer通過observe()方法進(jìn)行綁定。

LiveData有兩種使用方法:一種是直接使用,如接下來的例子;還有一種是繼承LiveData的實(shí)現(xiàn)資源共享的方式。
直接使用的時(shí)候,LiveData一般和ViewModel一起使用。
首先定義個(gè)MyNameViewModel

class MyNameViewModel : ViewModel() {
    // Create a LiveData with a String
    private var mCurrentName: MutableLiveData<String>? = null
    // Create a LiveData with a String list
    private var mNameListData: MutableLiveData<List<String>>? = null

    open fun currentName(): MutableLiveData<String> {
        if (mCurrentName == null) {
            mCurrentName = MutableLiveData()
        }
        return mCurrentName as MutableLiveData<String>
    }

    open fun nameList(): MutableLiveData<List<String>> {
        if (mNameListData == null) {
            mNameListData = MutableLiveData()
        }
        return mNameListData as MutableLiveData<List<String>>
    }
}
class FirstActivity : AppCompatActivity() {
    companion object {
        val TAG = FirstActivity.javaClass.simpleName
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val myNameViewModel = ViewModelProviders.of(this).get(MyNameViewModel::class.java)
        myNameViewModel.currentName().observe(this, Observer {
            print(it)
        })

        myNameViewModel.nameList().observe(this, Observer {
            if (it != null) {
                for (item in it) {
                    print(item)
                }
            }
        })
    }

ViewModel里面,定義兩個(gè)方法,currentName,和nameList兩個(gè)方法,并返回LiveData對(duì)象。然后在activity中通過ViewModelProviders.of(this).get(MyNameViewModel::class.java)拿到viewModel,最后通過observe設(shè)置監(jiān)聽,observe方法里面的兩個(gè)參數(shù)LifecycleOwner ownerObserver<T>,最后在onChanged方法中回調(diào)數(shù)據(jù)(這里kotlin代碼使用的是lamdba表達(dá)式)。

用兩個(gè)按鈕模仿修改ViewModel中保存的LiveData數(shù)據(jù):

   btn_change_name.setOnClickListener {
            myNameViewModel.currentName().setValue("Hubery")
   }

    btn_update_list.setOnClickListener {
          var nameList = ArrayList<String>()
            for (i in 0..9) {
                nameList.add("Hubery<$i>")
            }
            myNameViewModel.nameList().setValue(nameList)
    }

現(xiàn)在來看看LiveData資源共享,也就是繼承LiveData的例子

class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
    private val mStockManager: StockManager

    private val mListener = object : SimplePriceListener() {
        fun onPriceChanged(price: BigDecimal) {
            setValue(price)
        }
    }

    init {
        mStockManager = StockManager(symbol)
    }

    override fun onActive() {
        mStockManager.requestPriceUpdates(mListener)
    }

    override fun onInactive() {
        mStockManager.removeUpdates(mListener)
    }
}

當(dāng)LiveData對(duì)象具有活動(dòng)的觀察者時(shí)調(diào)用OnActive方法。LiveData中的數(shù)據(jù)會(huì)調(diào)用setValue方法去更新。
當(dāng)LiveData在沒有任何的Observer監(jiān)聽的時(shí)候,會(huì)調(diào)用Inactive方法,在這里的例子會(huì)removeUpdate方法。

LiveData的原理

借鑒ShymanZhu同學(xué)的關(guān)系圖

LiveData_one.png

LiveData:是LiveData組件里面非常核心的一個(gè)類,主要實(shí)現(xiàn)了observe方法用于注冊(cè)監(jiān)聽,setValue用于主線程設(shè)置值,而postValue子線程和主線程都可以。

MutabeLiveData:繼承了LiveDataLiveData是一個(gè)抽象類不能直接使用,在子類里面重寫了postValuesetValue兩個(gè)方法;

MediatorLiveDataMediatorLiveData繼承了MutabeLiveData;

LifecycleBoundObserverLifecycleBoundObserverLiveData的內(nèi)部類,
它繼承了ObserverWrapper并實(shí)現(xiàn)了GenericLifecycleObserver,而這個(gè)GenericLifecycleObserver又實(shí)現(xiàn)了LifecycleObserver,有沒有很熟悉?在Lifecycle組件中通過LifecycleObserver便可以觀察到LifecycleOwner中持有的Lifecycle對(duì)象的生命周期變化。

ObserverLiveData有數(shù)據(jù)更新的時(shí)候就是通過Observer接口的onChanged方法告知界面(Activity,F(xiàn)ragment)。

再次感謝ShymanZhu同學(xué)的時(shí)序圖

LiveData_two.png

上面大致的思路是:在Fragment中調(diào)用observe()方法的時(shí)候,會(huì)先在方法內(nèi)創(chuàng)建一個(gè)LifecycleBoundObserver對(duì)象,然后通過getLifecycle().addObserver()將這個(gè)創(chuàng)建好的對(duì)象添加進(jìn)去。當(dāng)生命周期會(huì)發(fā)生改變的時(shí)候,會(huì)調(diào)用相應(yīng)的方法,移除觀察者或者通知觀察者更新數(shù)據(jù);另外的調(diào)用LiveDatasetValue()、postValue()方法后,也會(huì)通知觀察者更新數(shù)據(jù)。

我們首先根據(jù)上面的思路理一下,首選需要注冊(cè)觀察者,創(chuàng)建LifecycleBoundObserver對(duì)象,生命周期發(fā)生變化之后通知觀察者修改數(shù)據(jù)。

添加觀察者

添加觀察者有兩個(gè)方法可以調(diào)用,observeobserveForever,先來看看這兩個(gè)方法的實(shí)現(xiàn):

   @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        owner.getLifecycle().addObserver(wrapper);
    }

observe方法中需要將LifecycleOwner傳入,而LifecycleOwner的實(shí)現(xiàn)類可以通過getLifecycle(),拿到Lifecycle的生命周期;而observeForever則不需要傳入:

   @MainThread
    public void observeForever(@NonNull Observer<T> observer) {
        AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        wrapper.activeStateChanged(true);
    }

通過observeForever()添加的觀察者,會(huì)永久收到數(shù)據(jù)變化的回調(diào),除非用戶手動(dòng)removeObserve()觀察者會(huì)一直收到數(shù)據(jù)的變化的回調(diào)通知。

生命周期變化

先看看LifecycleBoundObserver 類的源碼實(shí)現(xiàn):

  class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
        @NonNull final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) {
            super(observer);
            mOwner = owner;
        }

        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        @Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            activeStateChanged(shouldBeActive());
        }

        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }

        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }
void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive
            // owner
            mActive = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == 0;
            LiveData.this.mActiveCount += mActive ? 1 : -1;
            if (wasInactive && mActive) {
                onActive();
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                onInactive();
            }
            if (mActive) {
                dispatchingValue(this);
            }
        }

添加了觀察者之后,生命周期發(fā)生改變的時(shí)候就會(huì)調(diào)用onStateChanged()方法,當(dāng)前的狀態(tài)處于DESTROYED的時(shí)候,觀察者會(huì)被remove,當(dāng)當(dāng)前的狀態(tài)為active的時(shí)候,調(diào)用activeStateChanged()方法。

LiveData的數(shù)據(jù)更新

上面我們提到過,LiveData的數(shù)據(jù)更新有兩種方式,第一種就是使用setValue的方式只能在主線程也就是UI線程里面調(diào)用,另外一種就是postValue的方式可以在主線程或者子線程里面調(diào)用。

public class MutableLiveData<T> extends LiveData<T> {
    @Override
    public void postValue(T value) {
        super.postValue(value);
    }

    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}

setValuepostValueLiveData中的實(shí)現(xiàn):

@MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

 protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }

   private final Runnable mPostValueRunnable = new Runnable() {
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            //noinspection unchecked
            setValue((T) newValue);
        }
    };

通過源碼看到,postValue最后也會(huì)調(diào)用setValue方法,去修改LiveData中的值。

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

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

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