1膀篮、概述
LiveData
是一種可觀察的數(shù)據(jù)存儲器類,LiveData
使用觀察者模式,每當數(shù)據(jù)發(fā)生變化時有勾,LiveData
會通知 Observer
對象,我們可以在這些 Observer
對象中更新UI
ViewModel
對象為特定的界面組件(如 Fragment 或 Activity)提供數(shù)據(jù)古程,并包含數(shù)據(jù)處理業(yè)務邏輯蔼卡,會配合LiveData
一起使用
接下來,我們會先介紹如果使用LiveData挣磨,并編寫一個LiveData Demo雇逞,接著再結(jié)合ViewModel對LiveData Demo的代碼進行重構(gòu)
2、LiveData使用說明
LiveData<T>
是一個抽象類茁裙,它有2個子類分別是:MutableLiveData<T>
和MediatorLiveData<T>
塘砸,在編寫代碼時,是創(chuàng)建的子類呜达。我們先來看MutableLiveData<T>
使用方法谣蠢,在后面的示例中再介紹如何使用MediatorLiveData<T>
2.1、創(chuàng)建LiveData對象
如果我們要觀察的對象類為String
查近,就通過如下代碼創(chuàng)建一個MutableLiveData
對象
MutableLiveData<String> liveData = new MutableLiveData<>();
2.2眉踱、觀察LiveData對象
通過observe
方法來監(jiān)聽LiveData
的數(shù)據(jù)變化,每當LiveData
發(fā)生變化時霜威,都會回調(diào)onChanged
方法谈喳,并返回值的內(nèi)容String s
liveData.observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
Log.i(TAG, "onChanged: " + s);
}
});
2.3、更新LiveData對象
通過LiveData
的setValue
方法戈泼,給LiveData
賦值婿禽,每次賦完值后赏僧,都會回調(diào)onChanged
方法
liveData.setValue("add for test");
當給LiveData
賦值為"add for test"
時,onChanged
會輸出日志:
2021-03-20 21:59:21.483 26430-26430/com.example.livedatademo I/LiveDataDemo: onChanged: add for test
3扭倾、編寫LiveData Demo
我們創(chuàng)建一個Demo淀零,主界面只有一個TextView
,TextView
用作展示一個數(shù)字膛壹,這個數(shù)字會從59開始顯示驾中,然后每隔1秒數(shù)字會減1,直到數(shù)字變?yōu)?模聋。
接下來肩民,我們看下不使用LiveData
和使用LiveData
來實現(xiàn)這個Demo的區(qū)別
3.1、不使用LiveData
代碼說明如下:
1链方、在MainActivity
增加一個countDown
的方法持痰,通過CountDownTimer
創(chuàng)建一個倒計時器
2、new CountDownTimer(1 * 60 * 1000, 1 * 1000)
中2個參數(shù)的含義:第一個參數(shù)表示這個Timer的總時長
為60秒祟蚀;第2個參數(shù)表示每隔1秒
中會更新一次工窍,并回調(diào)onTick
方法
3、每次調(diào)用onTick
方法暂题,會調(diào)用textView.setText(String.valueOf(l / 1000));
設置一次TextView
的內(nèi)容對應代碼如下:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "LiveDataDemo";
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
countDown();
}
private void countDown() {
new CountDownTimer(1 * 60 * 1000, 1 * 1000) {
@Override
public void onTick(long l) {
Log.i(TAG, "onTick: " + l);
textView.setText(String.valueOf(l / 1000));
}
@Override
public void onFinish() {
}
}.start();
}
}
- 弊端:
業(yè)務邏輯(倒計時的功能)
和UI邏輯(TextView更新)
沒有分開移剪,耦合到一起了
3.2、使用MutableLiveData
為了方便演示薪者,我們直接在MainActivity中操作LiveData,實際項目中不要這樣編寫代碼剿涮,應該把LiveData放到ViewModel中
代碼說明如下:
1言津、在MainActivity
中增加一個long
類型的MutableLiveData
2、每次回調(diào)onTick
方法時取试,調(diào)用liveData.setValue(l);
悬槽,把最新的值設置給LiveData
3、調(diào)用LivewData
的observe
方法瞬浓,設置一個監(jiān)聽器初婆,每當LiveData
的值變化時,會回調(diào)onChanged
方法猿棉,在onChanged
中設置TextView
的內(nèi)容對應代碼如下:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "LiveDataDemo";
private final MutableLiveData<Long> liveData = new MutableLiveData<>();
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
// TODO:為了方便演示磅叛,我們直接在MainActivity中操作LiveData,實際項目中不要這樣編寫代碼萨赁,應該把LiveData放到ViewModel中
liveData.observe(this, new Observer<Long>() {
@Override
public void onChanged(Long aLong) {
textView.setText(String.valueOf(aLong / 1000));
}
});
countDown();
}
public void countDown() {
new CountDownTimer(1 * 60 * 1000, 1 * 1000) {
@Override
public void onTick(long l) {
Log.i(TAG, "onTick: " + l);
// TODO:為了方便演示弊琴,我們直接在MainActivity中操作LiveData,實際項目中不要這樣編寫代碼杖爽,應該把LiveData放到ViewModel中
liveData.setValue(l);
}
@Override
public void onFinish() {
}
}.start();
}
}
3.3敲董、使用MediatorLiveData
MediatorLiveData
可以合并多個LiveData
源紫皇,只要任何原始的LiveData
源對象發(fā)生更改,就會觸發(fā)MediatorLiveData
對象的觀察者腋寨。
例如聪铺,如果界面中有可以從本地數(shù)據(jù)庫或網(wǎng)絡更新的 LiveData
對象,則可以向MediatorLiveData
對象添加以下源:
- 與存儲在數(shù)據(jù)庫中的數(shù)據(jù)關(guān)聯(lián)的
LiveData
對象萄窜。 - 與從網(wǎng)絡訪問的數(shù)據(jù)關(guān)聯(lián)的
LiveData
對象计寇。
Activity
只需觀察MediatorLiveData
對象即可從這兩個源接收更新。接下來脂倦,我們會實現(xiàn)這個例子番宁。
3.3.1、監(jiān)聽2個數(shù)據(jù)源的變化
-
代碼說明如下:
1赖阻、創(chuàng)建1個MediatorLiveData<String>
對象final MediatorLiveData<String> liveDataMerger = new MediatorLiveData<>();
2蝶押、創(chuàng)建2個
MutableLiveData
:liveData1表示網(wǎng)絡數(shù)據(jù)源,liveData2表示本地數(shù)據(jù)源private MutableLiveData<String> liveData1 = new MutableLiveData<>(); private MutableLiveData<String> liveData2 = new MutableLiveData<>();
3火欧、調(diào)用
MediatorLiveData
的addSource
方法棋电,分別將liveData1
和liveData2
加到MediatorLiveData
要監(jiān)聽的數(shù)據(jù)源中liveDataMerger.addSource(liveData1, new Observer<String>() { @Override public void onChanged(String s) { Log.i(TAG, "addSource1 onChanged: " + s); liveDataMerger.setValue(s); } }); liveDataMerger.addSource(liveData2, new Observer<String>() { @Override public void onChanged(String s) { Log.i(TAG, "addSource2 onChanged: " + s); liveDataMerger.setValue(s); } });
4、設置
MediatorLiveData
的監(jiān)聽苇侵,當2個數(shù)據(jù)源發(fā)生變化時赶盔,會回調(diào)onChanged
方法,并將變化的內(nèi)容展示到TextView
上liveDataMerger.observe(this, new Observer<String>() { @Override public void onChanged(String s) { Log.i(TAG, "liveDataMerger onChanged: " + s); textView.setText(s); }
});
3.3.2榆浓、 編寫模擬2個數(shù)據(jù)源更新的代碼
編寫一個mergeTes
的方法于未,里面創(chuàng)建了2個Timer
,用作模擬網(wǎng)絡數(shù)據(jù)更新和本地數(shù)據(jù)更新的情況陡鹃,每隔3
秒會往網(wǎng)絡數(shù)據(jù)liveData1
設置值烘浦、每隔10
秒會往本地數(shù)據(jù)liveData2
設置值。對應代碼如下:
public void mergeTest() {
new CountDownTimer(1 * 60 * 1000, 3 * 1000) {
@Override
public void onTick(long l) {
liveData1.setValue("網(wǎng)絡有數(shù)據(jù)更新了" + l/1000);
}
@Override
public void onFinish() {
}
}.start();
new CountDownTimer(1 * 60 * 1000, 10 * 1000) {
@Override
public void onTick(long l) {
liveData2.setValue("本地數(shù)據(jù)庫更新了" + l/1000);
}
@Override
public void onFinish() {
}
}.start();
}
3.3.4萍鲸、MediatorLiveData運行效果
每隔3秒闷叉,TextView
更新為如下內(nèi)容:
每隔10秒,TextView
更新為如下內(nèi)容:
4脊阴、ViewModel使用
4.1 創(chuàng)建ViewModel類
創(chuàng)建一個MyViewModel類握侧,繼承自ViewModel
import androidx.lifecycle.ViewModel;
public class MyViewMode extends ViewModel {
}
4.2 在Activity中使用
public class MainActivity extends AppCompatActivity {
private MyViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewModel = new ViewModelProvider(this).get(MyViewModel.class);
}
}
如果遇到new ViewModelProvider(this)
報錯,就在app/build.gradle中加入依賴implementation "androidx.lifecycle:lifecycle-viewmodel:2.3.0"
5嘿期、結(jié)合ViewModel品擎,重構(gòu)LiveData Demo
5.1、在ViewModel中增加LiveData
在MyViewModel中增加3個MutableLiveData秽五,分別對應在MainActivity中使用到的孽查。并編寫這3個LiveData的get方法
public class MyViewModel extends ViewModel {
private MutableLiveData<Long> liveData = new MutableLiveData<>();
private MutableLiveData<String> liveData1 = new MutableLiveData<>();
private MutableLiveData<String> liveData2 = new MutableLiveData<>();
public MutableLiveData<Long> getLiveData() {
return liveData;
}
public MutableLiveData<String> getLiveData1() {
return liveData1;
}
public MutableLiveData<String> getLiveData2() {
return liveData2;
}
}
5.2、在ViewModel中添加操作數(shù)據(jù)的邏輯
countDown坦喘、mergeTest這2個方法在操作數(shù)據(jù)盲再,從MainActivity中把這2個方法copy到 MyViewModel中
public class MyViewModel extends ViewModel {
private static final String TAG = "MyViewMode";
... ...
public void countDown() {
new CountDownTimer(1 * 60 * 1000, 1 * 1000) {
@Override
public void onTick(long l) {
Log.i(TAG, "onTick: " + l);
liveData.postValue(l);
}
@Override
public void onFinish() {
}
}.start();
}
public void mergeTest() {
new CountDownTimer(1 * 60 * 1000, 3 * 1000) {
@Override
public void onTick(long l) {
liveData1.postValue("網(wǎng)絡有數(shù)據(jù)更新了" + l / 1000);
}
@Override
public void onFinish() {
}
}.start();
new CountDownTimer(1 * 60 * 1000, 10 * 1000) {
@Override
public void onTick(long l) {
liveData2.postValue("本地數(shù)據(jù)庫更新了" + l / 1000);
}
@Override
public void onFinish() {
}
}.start();
}
}
5.3 修改MainActivity中和liveData有關(guān)的代碼
1西设、刪除countDown,改用viewModel.countDown();
viewModel = new ViewModelProvider(this).get(MyViewModel.class);
viewModel.countDown();
2答朋、用viewModel.getLiveData().observe替換liveData.observe
viewModel.getLiveData().observe(this, new Observer<Long>() {
@Override
public void onChanged(Long aLong) {
textView.setText(String.valueOf(aLong/1000));
}
});
3贷揽、刪除liveData相關(guān)代碼
經(jīng)過上述修改后,liveData相關(guān)的重構(gòu)已完成梦碗,MainActivity代碼如下:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "LiveDataDemo";
private TextView textView;
private MutableLiveData<String> liveData1 = new MutableLiveData<>();
private MutableLiveData<String> liveData2 = new MutableLiveData<>();
private MyViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
viewModel = new ViewModelProvider(this).get(MyViewModel.class);
viewModel.countDown();
.... ...
}
5.4禽绪、修改MyViewModel
增加liveDataMerger字段,并編寫getLiveDataMerger()方法洪规,這個方法里面的內(nèi)容印屁,是從MainActivity中copy過來的
public class MyViewModel extends ViewModel {
private static final String TAG = "MyViewMode";
.... ...
private MediatorLiveData<String> liveDataMerger;
public MediatorLiveData<String> getLiveDataMerger() {
if (liveDataMerger == null) {
liveDataMerger = new MediatorLiveData<>();
}
liveDataMerger.addSource(liveData1, new Observer<String>() {
@Override
public void onChanged(String s) {
Log.i(TAG, "addSource1 onChanged: " + s);
liveDataMerger.setValue(s);
}
});
liveDataMerger.addSource(liveData2, new Observer<String>() {
@Override
public void onChanged(String s) {
Log.i(TAG, "addSource2 onChanged: " + s);
liveDataMerger.setValue(s);
}
});
return liveDataMerger;
}
... ...
}
5.5、修改MainActivity中和MediatorLiveData有關(guān)的代碼
1斩例、使用viewModel.getLiveDataMerger().observe替換liveDataMerger.observe
viewModel.getLiveDataMerger().observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
Log.i(TAG, "liveDataMerger onChanged: " + s);
textView.setText(s);
}
});
2雄人、使用viewModel.mergeTest();替換mergeTest()
viewModel.mergeTest();
3、刪除掉liveDataMerger相關(guān)的代碼
5.6 重構(gòu)后MainActivity的代碼
public class MainActivity extends AppCompatActivity {
private static final String TAG = "LiveDataDemo";
private TextView textView;
private MyViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
viewModel = new ViewModelProvider(this).get(MyViewModel.class);
viewModel.getLiveData().observe(this, new Observer<Long>() {
@Override
public void onChanged(Long aLong) {
textView.setText(String.valueOf(aLong / 1000));
}
});
viewModel.getLiveDataMerger().observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
Log.i(TAG, "liveDataMerger onChanged: " + s);
textView.setText(s);
}
});
viewModel.mergeTest();
// viewModel.countDown();
}
}
5.7 重構(gòu)后MyViewModel的代碼
public class MyViewModel extends ViewModel {
private static final String TAG = "MyViewMode";
private MutableLiveData<Long> liveData = new MutableLiveData<>();
private MutableLiveData<String> liveData1 = new MutableLiveData<>();
private MutableLiveData<String> liveData2 = new MutableLiveData<>();
private MediatorLiveData<String> liveDataMerger;
public MediatorLiveData<String> getLiveDataMerger() {
if (liveDataMerger == null) {
liveDataMerger = new MediatorLiveData<>();
}
liveDataMerger.addSource(liveData1, new Observer<String>() {
@Override
public void onChanged(String s) {
Log.i(TAG, "addSource1 onChanged: " + s);
liveDataMerger.setValue(s);
}
});
liveDataMerger.addSource(liveData2, new Observer<String>() {
@Override
public void onChanged(String s) {
Log.i(TAG, "addSource2 onChanged: " + s);
liveDataMerger.setValue(s);
}
});
return liveDataMerger;
}
public MutableLiveData<Long> getLiveData() {
return liveData;
}
public MutableLiveData<String> getLiveData1() {
return liveData1;
}
public MutableLiveData<String> getLiveData2() {
return liveData2;
}
public void countDown() {
new CountDownTimer(1 * 60 * 1000, 1 * 1000) {
@Override
public void onTick(long l) {
Log.i(TAG, "onTick: " + l);
liveData.postValue(l);
}
@Override
public void onFinish() {
}
}.start();
}
public void mergeTest() {
new CountDownTimer(1 * 60 * 1000, 3 * 1000) {
@Override
public void onTick(long l) {
liveData1.postValue("網(wǎng)絡有數(shù)據(jù)更新了" + l / 1000);
}
@Override
public void onFinish() {
}
}.start();
new CountDownTimer(1 * 60 * 1000, 10 * 1000) {
@Override
public void onTick(long l) {
liveData2.postValue("本地數(shù)據(jù)庫更新了" + l / 1000);
}
@Override
public void onFinish() {
}
}.start();
}
}