如果你看過(guò)了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ù)更新贸伐。通過(guò)這點(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ì)收到來(lái)自LiveData
的數(shù)據(jù)變化通知藐翎。這樣規(guī)避了很多因?yàn)轫?yè)面銷毀之后砰苍,修改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的使用
通常使用LiveData
有三個(gè)步驟:
1,創(chuàng)建LiveData
實(shí)例來(lái)保存數(shù)據(jù)蛹含,常常是配合ViewModel
一起工作毅厚;
2,定義一個(gè)Observer
的觀察者對(duì)象浦箱,如果有數(shù)據(jù)更新會(huì)通過(guò)觀察者的onChanged()
方法來(lái)同步到UI
上面吸耿;
3,將觀察者Observer
通過(guò)observe()
方法進(jìn)行綁定酷窥。
LiveData
有兩種使用方法:一種是直接使用咽安,如接下來(lái)的例子;還有一種是繼承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
中通過(guò)ViewModelProviders.of(this).get(MyNameViewModel::class.java)
拿到viewModel
,最后通過(guò)observe
設(shè)置監(jiān)聽(tīng)放接,observe
方法里面的兩個(gè)參數(shù)LifecycleOwner owner
和Observer<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)在來(lái)看看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
在沒(méi)有任何的Observer
監(jiān)聽(tīng)的時(shí)候苟蹈,會(huì)調(diào)用Inactive
方法糊渊,在這里的例子會(huì)removeUpdate
方法。
LiveData的原理
借鑒ShymanZhu同學(xué)的關(guān)系圖
LiveData
:是LiveData
組件里面非常核心的一個(gè)類,主要實(shí)現(xiàn)了observe
方法用于注冊(cè)監(jiān)聽(tīng)慧脱,setValue
用于主線程設(shè)置值渺绒,而postValue
子線程和主線程都可以。
MutabeLiveData
:繼承了LiveData
菱鸥,LiveData
是一個(gè)抽象類不能直接使用宗兼,在子類里面重寫(xiě)了postValue
和setValue
兩個(gè)方法;
MediatorLiveData
:MediatorLiveData
繼承了MutabeLiveData
氮采;
LifecycleBoundObserver
:LifecycleBoundObserver
是LiveData
的內(nèi)部類殷绍,
它繼承了ObserverWrapper
并實(shí)現(xiàn)了GenericLifecycleObserver
,而這個(gè)GenericLifecycleObserver
又實(shí)現(xiàn)了LifecycleObserver
,有沒(méi)有很熟悉鹊漠?在Lifecycle
組件中通過(guò)LifecycleObserver
便可以觀察到LifecycleOwner
中持有的Lifecycle
對(duì)象的生命周期變化主到。
Observer
:LiveData
有數(shù)據(jù)更新的時(shí)候就是通過(guò)Observer
接口的onChanged
方法告知界面(Activity,F(xiàn)ragment)
贸呢。
再次感謝ShymanZhu同學(xué)的時(shí)序圖
上面大致的思路是:在
Fragment
中調(diào)用observe()
方法的時(shí)候镰烧,會(huì)先在方法內(nèi)創(chuàng)建一個(gè)LifecycleBoundObserver
對(duì)象,然后通過(guò)getLifecycle().addObserver()
將這個(gè)創(chuàng)建好的對(duì)象添加進(jìn)去楞陷。當(dāng)生命周期會(huì)發(fā)生改變的時(shí)候怔鳖,會(huì)調(diào)用相應(yīng)的方法,移除觀察者或者通知觀察者更新數(shù)據(jù)固蛾;另外的調(diào)用LiveData
的setValue()
结执、postValue()
方法后,也會(huì)通知觀察者更新數(shù)據(jù)艾凯。
我們首先根據(jù)上面的思路理一下献幔,首選需要注冊(cè)觀察者,創(chuàng)建LifecycleBoundObserver
對(duì)象趾诗,生命周期發(fā)生變化之后通知觀察者修改數(shù)據(jù)蜡感。
添加觀察者
添加觀察者有兩個(gè)方法可以調(diào)用,observe
和observeForever
恃泪,先來(lái)看看這兩個(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)類可以通過(guò)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);
}
通過(guò)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ù)更新
上面我們提到過(guò)篱昔,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);
}
}
setValue
和postValue
在LiveData
中的實(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);
}
};
通過(guò)源碼看到,postValue
最后也會(huì)調(diào)用setValue
方法浪箭,去修改LiveData
中的值穗椅。