1.前言
LiveData
是Google推出的一系列的框架組件的其中一個,它是一個可以被觀察的數(shù)據(jù)持有類滥沫,能夠感知Activity
、Fragment
等組件的生命周期。
一個觀察者去觀察LiveData
后,當(dāng)觀察者的生命周期處于STARTED
或RESUMED
狀態(tài)時(即onStart()
、onResume()
、onPause()
),LiveData
的數(shù)據(jù)發(fā)生變化屎媳,則會通知觀察者嘉汰;若觀察者處于其他狀態(tài),即使LiveData
的數(shù)據(jù)發(fā)生變化荧降,也不會發(fā)出通知接箫。
正是由于這一特性,因此LiveData
可以做到僅在組件處于活躍狀態(tài)時才進(jìn)行更新UI的操作朵诫。
使用LiveData
前需要先了解Lifecycle
辛友,如果還不知道Lifecycle
,可以看下這篇文章:Android框架組件--Lifecycle的使用
本文主要介紹如何使用LiveData
剪返。
2.LiveData使用例子
下面來看下如何使用LiveData
废累。
3.1 添加依賴
在相應(yīng)的moudle
目錄下的build.gradle
中添加以下依賴:
dependencies {
//...
def lifecycle_version = "1.1.1"
//僅僅依賴LiveData
implementation "android.arch.lifecycle:livedata:$lifecycle_version"
}
3.2 創(chuàng)建LiveData對象
google官網(wǎng)提倡LiveData
配合ViewModel
一起使用。為了專注LiveData
脱盲,這里先不用ViewModel
邑滨,后面再補(bǔ)充說明如何跟ViewModel
一起使用。直接看例子:
public class TestModel {
private MutableLiveData<String> status;
public MutableLiveData<String> getStatus() {
if (status == null)
status = new MutableLiveData<>();
return status;
}
}
MutableLiveData
繼承自LiveData
钱反,表示可變數(shù)據(jù)掖看。這里創(chuàng)建一個保存String
類型數(shù)據(jù)的LiveData
。
3.3 觀察LiveData對象
通常面哥,會在Activity
的onCreate()
方法中開始對LiveData
的觀察:
public class TestActivity extends AppCompatActivity {
private static final String TAG = "test";
private TextView mTextView;
private TestModel mTestModel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_activity);
mTextView = findViewById(R.id.tv_test);
initVariable();
}
private void initVariable() {
//創(chuàng)建一個觀察者去更新UI
final Observer<String> statusObserver = new Observer<String>() {
@Override
public void onChanged(@Nullable final String newName) {
Log.d(TAG, "onChanged: " + newName);
mTextView.setText(newName);
}
};
//創(chuàng)建TestModel對象
mTestModel = new TestModel();
//觀察LiveData對象
//這里的this指的是LifecycleOwner哎壳,即LiveData會跟生命周期聯(lián)系起來
mTestModel.getStatus().observe(this, statusObserver);
}
}
觀察者可以通過observe()
方法對LiveData
進(jìn)行監(jiān)聽,observe()
方法需要傳遞一個LifecycleOwner
參數(shù)進(jìn)去尚卫,這表示LiveData
會跟生命周期聯(lián)系起來归榕。
另外還有一個observeForever()
方法,只需傳遞一個觀察者進(jìn)去就行吱涉,這意味著它跟生命周期沒有任何關(guān)系刹泄,可以持續(xù)的觀察,只要數(shù)據(jù)發(fā)生變化怎爵,都會通知觀察者回調(diào)onChanged()
循签。
3.4 更新LiveData對象
MutableLiveData
提供了setValue(T)
(主線程使用)和postValue(T)
(子線程使用)兩個方法來修改數(shù)據(jù)。LiveData
并沒有提供類似方法疙咸。當(dāng)調(diào)用MutableLiveData
的setValue(T)
或postValue(T)
方法后,Observer
的onChanged()
方法將會被回調(diào)风科,從而實(shí)現(xiàn)更新UI的操作撒轮。
注意乞旦,這是在觀察者處于STARTED
或RESUMED
狀態(tài)時,LiveData
才會通知觀察者數(shù)據(jù)變化题山;當(dāng)觀察者處于其他狀態(tài)時兰粉,即使LiveData
的數(shù)據(jù)變化了,也不會通知顶瞳。
當(dāng)組件的狀態(tài)為DESTROYED
時會自動移除觀察者玖姑,這樣Activity
或Fragment
就可以安全地觀察LiveData
而不用擔(dān)心造成內(nèi)存泄露。
我們來看個完整的例子:
public class TestActivity extends AppCompatActivity {
private static final String TAG = "test";
private TextView mTextView;
private TestModel mTestModel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_activity);
mTextView = findViewById(R.id.tv_test);
initVariable();
}
private void initVariable() {
//創(chuàng)建一個觀察者去更新UI
final Observer<String> statusObserver = new Observer<String>() {
@Override
public void onChanged(@Nullable final String newName) {
Log.d(TAG, "onChanged: " + newName);
mTextView.setText(newName);
}
};
//創(chuàng)建TestModel對象
mTestModel = new TestModel();
//觀察LiveData對象
//這里的this指的是LifecycleOwner慨菱,即LiveData會跟生命周期聯(lián)系起來
mTestModel.getStatus().observe(this, statusObserver);
mTestModel.getStatus().setValue("onCreate");
}
@Override
protected void onStart() {
super.onStart();
mTestModel.getStatus().setValue("onStart");
}
@Override
protected void onResume() {
super.onResume();
mTestModel.getStatus().setValue("onResume");
}
@Override
protected void onPause() {
super.onPause();
mTestModel.getStatus().setValue("onPause");
}
@Override
protected void onStop() {
super.onStop();
mTestModel.getStatus().setValue("onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
mTestModel.getStatus().setValue("onDestroy");
}
}
一個完整的生命周期走下來焰络,其輸出結(jié)果為:
07-26 22:03:34.798 20995-20995/com.test.start D/test: onChanged: onStart
07-26 22:03:34.801 20995-20995/com.test.start D/test: onChanged: onResume
07-26 22:03:36.456 20995-20995/com.test.start D/test: onChanged: onPause
可以看到,只在onStart()
符喝、onResume()
闪彼、onPause()
時觀察者才會收到數(shù)據(jù)更新的通知,其他狀態(tài)下即使更新了數(shù)據(jù)也不會收到通知协饲。
3. LiveData配合ViewModel使用
下面來看下跟ViewModel
是如何一起使用的畏腕。
3.1 添加依賴
使用ViewModel
還需添加ViewModel
的依賴:
dependencies {
//...
def lifecycle_version = "1.1.1"
//ViewModel 和 LiveData
implementation "android.arch.lifecycle:extensions:$lifecycle_version"
}
3.2 創(chuàng)建ViewModel
public class TestViewModel extends ViewModel {
private MutableLiveData<String> status;
public MutableLiveData<String> getStatus() {
if (status == null)
status = new MutableLiveData<>();
return status;
}
}
繼承ViewModel
后即可。
3.3 觀察并更新LiveData對象
public class TestActivity extends AppCompatActivity {
private static final String TAG = "test";
private TextView mTextView;
private TestViewModel mTestModel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_activity);
mTextView = findViewById(R.id.tv_test);
initVariable();
}
private void initVariable() {
final Observer<String> statusObserver = new Observer<String>() {
@Override
public void onChanged(@Nullable final String newName) {
Log.d(TAG, "onChanged: " + newName);
mTextView.setText(newName);
}
};
// mTestModel = new TestModel();
//改為通過ViewModel來創(chuàng)建對象
mTestModel = ViewModelProviders.of(this).get(TestViewModel.class);
mTestModel.getStatus().observe(this, statusObserver);
}
@Override
protected void onResume() {
super.onResume();
//更新數(shù)據(jù)
mTestModel.getStatus().setValue("onResume");
}
}
ViewModel
跟普通Model
流程都是一樣的茉稠,只是創(chuàng)建對象時不一樣而已描馅。
Google建議LiveData
配合ViewModel
一起使用。
4. 擴(kuò)展LiveData
除了使用MutableLiveData
外而线,我們還可以通過繼承LiveData
類來擴(kuò)展一些功能铭污。
比如:只有觀察者觀察了LiveData
的數(shù)據(jù)時,才開始進(jìn)行進(jìn)行獲取數(shù)據(jù)的操作吞获,這樣可以節(jié)省資源况凉,代碼如下所示:
4.1 繼承LiveData
public class TestLiveData extends LiveData<String> {
private static TestLiveData sInstance;
private LocationUtil mLocationUtil;
//設(shè)計為單例模式
public static TestLiveData getInstance() {
if (sInstance == null) {
sInstance = new TestLiveData();
}
return sInstance;
}
private TestLiveData() {
//創(chuàng)建一個獲取位置的對象
mLocationUtil = new LocationUtil();
}
@Override
protected void onActive() {
//開始獲取位置信息
mLocationUtil.start(mLocationListener);
}
@Override
protected void onInactive() {
//停止獲取位置信息
mLocationUtil.stop();
}
//創(chuàng)建一個位置監(jiān)聽器
private LocationListener mLocationListener = new LocationListener() {
@Override
public void onReceiveLocation(String location) {
//接受到位置信息后,更新數(shù)據(jù)
setValue(location);
}
};
}
將LiveData
設(shè)計成單例模式后各拷,可以在多個Activity
刁绒、Fragment
和Service
之間共享它。
下面我們來重點(diǎn)關(guān)系一下LiveData
的三個方法:onActive()
烤黍、onInactive()
知市、setValue()
。
-
onActive()
:當(dāng)有一個處于活躍狀態(tài)的觀察者監(jiān)聽LiveData
時會被調(diào)用速蕊,這表示開始獲取位置信息嫂丙。 -
onInactive()
:當(dāng)沒有任何處于活躍狀態(tài)的觀察者監(jiān)聽LiveData
時會被調(diào)用。由于沒有觀察者在監(jiān)聽了规哲,所以也沒必要繼續(xù)去獲取位置信息了跟啤,這只會消耗更多的電量等等,因此就可以停止獲取位置信息了。 -
setValue()
:更新LiveData
的值隅肥,并通知到觀察者竿奏。
4.2 使用自定義的LiveData
下面來看下怎么使用這個自定義的LiveData
:
public class TestActivity extends AppCompatActivity {
private static final String TAG = "test";
private TextView mTextView;
private TestLiveData mTestLiveData;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_activity);
mTextView = findViewById(R.id.tv_test);
initVariable();
}
private void initVariable() {
final Observer<String> statusObserver = new Observer<String>() {
@Override
public void onChanged(@Nullable final String newName) {
Log.d(TAG, "onChanged: " + newName);
mTextView.setText(newName);
}
};
//通過單例獲取對象
mTestLiveData =TestLiveData.getInstance();
//同樣是去觀察LiveData
mTestLiveData.observe(this, statusObserver);
}
}
跟之前的一樣,還是通過一個觀察者去監(jiān)聽這個mTestLiveData
對象腥放。
5. LiveData變換
LiveData
變換主要有兩種變換:map
和switchMap
泛啸,都是Transformations
類提供的。
5.1 map變換
public class TestViewModel extends ViewModel {
private MutableLiveData<Integer> mNumLiveData= new MutableLiveData<>();
//通過Transformations.map()將Integer類型的值轉(zhuǎn)換為String類型
private LiveData<String> mStrLiveData = Transformations.map(mNumLiveData, num -> num + "");
public MutableLiveData<Integer> getNumLiveData() {
return mNumLiveData;
}
public LiveData<String> getStrLiveData() {
return mStrLiveData;
}
}
map
變換可以直接修改返回的值和類型秃症。
5.2 switchMap變換
public class TestViewModel extends ViewModel {
private MutableLiveData<Integer> mNumLiveData = new MutableLiveData<>();
//switchMap變換
private LiveData<String> mNameLiveData = Transformations.switchMap(mNumLiveData, num -> getName(num));
//返回一個LiveData
private LiveData<String> getName(Integer num) {
MutableLiveData<String> liveData = new MutableLiveData<>();
liveData.setValue(num + "a");
return liveData;
}
public MutableLiveData<Integer> getNumLiveData() {
return mNumLiveData;
}
public LiveData<String> getNameLiveData() {
return mNameLiveData;
}
}
switchMap
變換需要返回一個LiveData
對象候址,這就是跟map
變換的區(qū)別。
6. 合并多個LiveData數(shù)據(jù)源
如果有多個LiveData
种柑,可以使用MediatorLiveData
來合并這些LiveData
岗仑,一旦其中一個LiveData
發(fā)生變化,MediatorLiveData
都會通知觀察者莹规。比如:一個UI界面赔蒲,依賴于網(wǎng)絡(luò)數(shù)據(jù)和數(shù)據(jù)庫,因此就會存在兩個LiveData
良漱。使用MediatorLiveData
將兩個LiveData
合并后舞虱,UI界面只需要觀察一個MediatorLiveData
即可。當(dāng)其中一個LiveData
數(shù)據(jù)發(fā)生變化時都會通知UI界面去更新母市。
6.1 MediatorLiveData使用例子
MediatorLiveData
的簡單使用如下所示:
LiveData liveData1 = ...;
LiveData liveData2 = ...;
MediatorLiveData liveDataMerger = new MediatorLiveData<>();
liveDataMerger.addSource(liveData1, value -> liveDataMerger.setValue(value));
liveDataMerger.addSource(liveData2, value -> liveDataMerger.setValue(value));
然后在UI界面直接觀察這個liveDataMerger
即可矾兜。
6.2 MediatorLiveData的方法
MediatorLiveData
相比于LiveData
,主要是多了以下兩個方法:
-
addSource()
:添加源LiveData
患久,并且開始監(jiān)聽給定的源LiveData
椅寺,當(dāng)源LiveData
的數(shù)據(jù)發(fā)生變化時,觀察者的onChanged()
方法將會被調(diào)用蒋失,前提是MediatorLiveData
處于活躍狀態(tài)返帕。 -
removeSource()
:移除LiveData
。
再來看個例子:
liveDataMerger.addSource(liveData1, new Observer() {
private int count = 1;
@Override public void onChanged(@Nullable Integer s) {
count++;
liveDataMerger.setValue(s);
if (count > 10) {
liveDataMerger.removeSource(liveData1);
}
}
});
監(jiān)聽liveData1
的數(shù)據(jù)篙挽,當(dāng)監(jiān)聽了10次之后荆萤,移除對liveData1
監(jiān)聽。
6.3 使用Transformations實(shí)現(xiàn)自定義變換
MediatorLiveData
除了可以合并數(shù)據(jù)外铣卡,實(shí)際上還可以用來實(shí)現(xiàn)自定義的變換方法链韭,上面Transformations
的map()
和switchMap()
如果不能滿足變換需求的話,那么就可以用MediatorLiveData
來實(shí)現(xiàn)煮落。
7. LiveData優(yōu)點(diǎn)
使用LiveData
具有以下優(yōu)點(diǎn):
1.確保UI跟數(shù)據(jù)狀態(tài)一致
組件處于活躍狀態(tài)時敞峭,當(dāng)數(shù)據(jù)發(fā)生變化,LiveData
會通知觀察者去更新UI蝉仇,從而使得他們保持一致旋讹。2.沒有內(nèi)存泄露
由于觀察者綁定到了Lifecycle
對象上殖蚕,因此在Lifecycle
被銷毀后,觀察者會被自行清理掉骗村。3.停止Activity不會造成崩潰
如果Activity
處于非活躍的狀態(tài)嫌褪,比如Activity
在后臺時,那么它不會接受到LiveData
的數(shù)據(jù)變更事件胚股。4.無需手動處理生命周期
UI組件僅僅需要觀察相應(yīng)的數(shù)據(jù)即可,無需手動去停止或恢復(fù)觀察裙秋。因?yàn)?code>LiveData會自動管理這所有的琅拌,它在觀察時能夠意識到相關(guān)的生命周期狀態(tài)變化。5.始終保持最新數(shù)據(jù)
如果生命周期處于不活躍的狀態(tài)摘刑,那么當(dāng)它變?yōu)榛钴S狀態(tài)時將會收到最新的數(shù)據(jù)进宝。比如:后臺Activity
變?yōu)榍芭_時將會收到最新的數(shù)據(jù)。6.適當(dāng)?shù)呐渲酶?br> 如果由于配置更改而重新去創(chuàng)建
Activity
或Fragment
枷恕,那么會立即接收最新的可用數(shù)據(jù)党晋。7.資源共享
你可以繼承LiveData
并使用單例模式來擴(kuò)展系統(tǒng)的服務(wù),這樣你就可以共享它徐块。這個自定義的LiveData
對象只需連接一次系統(tǒng)服務(wù)未玻,其他需要這些資源的觀察者只需觀察這個LiveData
即可『兀可以參看第4小節(jié):擴(kuò)展LiveData扳剿。