ViewModel
ViewModel的引入
如果系統(tǒng)銷毀或重新創(chuàng)建界面控制器,則存儲(chǔ)在其中的任何臨時(shí)性界面相關(guān)數(shù)據(jù)都會(huì)丟失。例如,應(yīng)用的某個(gè) Activity 中可能包含用戶列表。因配置更改而重新創(chuàng)建 Activity 后,新 Activity 必須重新提取用戶列表。對(duì)于簡(jiǎn)單的數(shù)據(jù),Activity 可以使用 onSaveInstanceState() 方法從 onCreate() 中的捆綁包恢復(fù)其數(shù)據(jù),但此方法僅適合可以序列化再反序列化的少量數(shù)據(jù),而不適合數(shù)量可能較大的數(shù)據(jù),如用戶列表或位圖。
架構(gòu)組件為界面控制器提供了 ViewModel 輔助程序類,該類負(fù)責(zé)為界面準(zhǔn)備數(shù)據(jù)。在配置更改期間會(huì)自動(dòng)保留 ViewModel 對(duì)象,以便它們存儲(chǔ)的數(shù)據(jù)立即可供下一個(gè) Activity 或 Fragment 實(shí)例使用。
實(shí)現(xiàn)ViewModel
package com.zyb.viewmodeltest;
import androidx.lifecycle.ViewModel;
public class MyViewModel extends ViewModel {
public int num = 0;
}
從 Activity 訪問(wèn)該列表,如下所示:
package com.zyb.viewmodeltest;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.lifecycle.ViewModelProviders;
public class MainActivity extends AppCompatActivity {
MyViewModel myViewModel;
Button button1,button2;
TextView showScore;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
button1 = findViewById(R.id.button);
button2 = findViewById(R.id.button2);
showScore = findViewById(R.id.textView);
showScore.setText(myViewModel.num "");
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myViewModel.num ;
showScore.setText(myViewModel.num "");
}
});
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myViewModel.num = 2;
showScore.setText(myViewModel.num "");
}
});
}
}
ui:
功能:點(diǎn)擊 1,數(shù)字 1,點(diǎn)擊 2,數(shù)字在原來(lái)基礎(chǔ)上 2
優(yōu)點(diǎn):不用我們保存之前加過(guò)數(shù)字的狀態(tài),因?yàn)樵谂渲酶钠陂g會(huì)自動(dòng)保留 ViewModel 對(duì)象
缺點(diǎn): showScore.setText();出現(xiàn)過(guò)多,代碼累贅,setOnClickListener出現(xiàn)過(guò)多代碼不好看
LiveData
使用 LiveData 具有以下優(yōu)勢(shì):
確保界面符合數(shù)據(jù)狀態(tài)
LiveData 遵循觀察者模式。當(dāng)生命周期狀態(tài)發(fā)生變化時(shí),LiveData 會(huì)通知 Observer 對(duì)象。您可以整合代碼以在這些 Observer 對(duì)象中更新界面。觀察者可以在每次發(fā)生更改時(shí)更新界面,而不是在每次應(yīng)用數(shù)據(jù)發(fā)生更改時(shí)更新界面。
不會(huì)發(fā)生內(nèi)存泄露
觀察者會(huì)綁定到 Lifecycle 對(duì)象,并在其關(guān)聯(lián)的生命周期遭到銷毀后進(jìn)行自我清理。
不會(huì)因 Activity 停止而導(dǎo)致崩潰
如果觀察者的生命周期處于非活躍狀態(tài)(如返回棧中的 Activity),則它不會(huì)接收任何 LiveData 事件。
不再需要手動(dòng)處理生命周期
界面組件只是觀察相關(guān)數(shù)據(jù),不會(huì)停止或恢復(fù)觀察。LiveData 將自動(dòng)管理所有這些操作,因?yàn)樗谟^察時(shí)可以感知相關(guān)的生命周期狀態(tài)變化。
數(shù)據(jù)始終保持最新?tīng)顟B(tài)
如果生命周期變?yōu)榉腔钴S狀態(tài),它會(huì)在再次變?yōu)榛钴S狀態(tài)時(shí)接收最新的數(shù)據(jù)。例如,曾經(jīng)在后臺(tái)的 Activity 會(huì)在返回前臺(tái)后立即接收最新的數(shù)據(jù)。
適當(dāng)?shù)呐渲酶?/font>
如果由于配置更改(如設(shè)備旋轉(zhuǎn))而重新創(chuàng)建了 Activity 或 Fragment,它會(huì)立即接收最新的可用數(shù)據(jù)。
共享資源
您可以使用單一實(shí)例模式擴(kuò)展 LiveData 對(duì)象以封裝系統(tǒng)服務(wù),以便在應(yīng)用中共享它們。LiveData 對(duì)象連接到系統(tǒng)服務(wù)一次,然后需要相應(yīng)資源的任何觀察者只需觀察 LiveData 對(duì)象。有關(guān)詳情,請(qǐng)參閱擴(kuò)展 LiveData。
實(shí)現(xiàn)LiveData
package com.zyb.livedatatest;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class MyViewModel extends ViewModel {
private MutableLiveData<Integer> num;
public MutableLiveData<Integer> getNum() {
if(num == null){
num = new MutableLiveData<>();
num.setValue(0);
}
return num;
}
public MutableLiveData<Integer> addNum(int n){
num.setValue(num.getValue() n);
return num;
}
}
從 Activity 訪問(wèn)該列表,如下所示:
package com.zyb.livedatatest;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProviders;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
ImageButton redButton,blueButton;
TextView score;
MyViewModel myViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
redButton = findViewById(R.id.imageButton);
blueButton = findViewById(R.id.imageButton3);
score = findViewById(R.id.textView);
myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
//觀察數(shù)據(jù)是否改變,改變就重寫
myViewModel.getNum().observe(this, new Observer<Integer>() {
@Override
public void onChanged(Integer integer) {
score.setText(integer "");
}
});
redButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myViewModel.addNum(1);
}
});
blueButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myViewModel.addNum(-1);
}
});
}
}
ui:
功能:左邊 1,右邊-1
優(yōu)點(diǎn):將setText()減少到一句
缺點(diǎn):setOnClickListener出現(xiàn)過(guò)多代碼不好看
DataBinding
在buid.gradle開(kāi)啟數(shù)據(jù)綁定:
之后重新構(gòu)建項(xiàng)目sync
進(jìn)入activity_main.xml中點(diǎn)擊
之后會(huì)多兩個(gè)標(biāo)簽和
package com.zyb.databindingtest;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class MyViewModel extends ViewModel {
MutableLiveData<Integer> cnt;
public MutableLiveData<Integer> getCnt() {
if(cnt == null){
cnt = new MutableLiveData<>();
cnt.setValue(0);
}
return cnt;
}
public void add(int n){
cnt.setValue(cnt.getValue() n);
}
}
MainActivity.java
package com.zyb.databindingtest;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders;
import android.os.Bundle;
import com.zyb.databindingtest.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
//綁定1:將界面對(duì)象綁定到控制器的ActivityMainBinding對(duì)象中(可以調(diào)用bind.xml標(biāo)簽名)
ActivityMainBinding bind;//注意這個(gè)類的名字和你Java文件的名字相同,不是固定的
MyViewModel myViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bind = DataBindingUtil.setContentView(this,R.layout.activity_main);
myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
//綁定2:將屏幕數(shù)據(jù)和控件的xml綁定
bind.setData1(myViewModel);//setData1是因?yàn)樵趚ml那個(gè)數(shù)據(jù)的name自己設(shè)定的data1,所以這setData1也是不固定的
//這句很重要,相當(dāng)于之前設(shè)置的觀察者語(yǔ)句
bind.setLifecycleOwner(this);
}
}
ui:
功能:顯示點(diǎn)擊按鈕次數(shù)
優(yōu)點(diǎn):控制器代碼減少,分工更明確
activity_main.xml變化:這個(gè)寫法有點(diǎn)像javaweb的模板引擎thymeleaf
最后的
thymeleaf相關(guān)圖:
相關(guān)變化圖:
最原始的,通過(guò)findViewById將單個(gè)組件的引用和控制器來(lái)連接起來(lái),數(shù)據(jù)顯示和變化都在控制器中
加入ViewModel之后將頁(yè)面數(shù)據(jù)(UIData)單獨(dú)提出來(lái)封裝
加入LiveData,將之前提出來(lái)的UIData換為L(zhǎng)iveData類型的,因?yàn)樗鼭M足觀察者類型,可以減少setText的書(shū)寫,降低代碼耦合性
加入DataBinding將數(shù)據(jù)操作綁定到相關(guān)界面的xml文件中,減少控制器的代碼量,分工更明確了
ui
參考鏈接
android開(kāi)發(fā)者官網(wǎng)
視頻
來(lái)源:https://www./content-4-637851.html
|