ViewModel、LiveData、DataBinding


ViewModel

ViewModel的引入

如果系統銷毀或重新創建界面控制器,則存儲在其中的任何臨時性界面相關數據都會丟失。例如,應用的某個 Activity 中可能包含用戶列表。因配置更改而重新創建 Activity 后,新 Activity 必須重新提取用戶列表。對於簡單的數據,Activity 可以使用 onSaveInstanceState() 方法從 onCreate() 中的捆綁包恢復其數據,但此方法僅適合可以序列化再反序列化的少量數據,而不適合數量可能較大的數據,如用戶列表或位圖。
架構組件為界面控制器提供了 ViewModel 輔助程序類,該類負責為界面准備數據。在配置更改期間會自動保留 ViewModel 對象,以便它們存儲的數據立即可供下一個 Activity 或 Fragment 實例使用。

實現ViewModel

package com.zyb.viewmodeltest;

import androidx.lifecycle.ViewModel;

public class MyViewModel extends ViewModel {
    public int num = 0;
}

從 Activity 訪問該列表,如下所示:

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:

功能:點擊+1,數字+1,點擊+2,數字在原來基礎上+2
優點:不用我們保存之前加過數字的狀態,因為在配置更改期間會自動保留 ViewModel 對象
缺點: showScore.setText();出現過多,代碼累贅,setOnClickListener出現過多代碼不好看

LiveData

使用 LiveData 具有以下優勢:

確保界面符合數據狀態
LiveData 遵循觀察者模式。當生命周期狀態發生變化時,LiveData 會通知 Observer 對象。您可以整合代碼以在這些 Observer 對象中更新界面。觀察者可以在每次發生更改時更新界面,而不是在每次應用數據發生更改時更新界面。
不會發生內存泄露
觀察者會綁定到 Lifecycle 對象,並在其關聯的生命周期遭到銷毀后進行自我清理。
不會因 Activity 停止而導致崩潰
如果觀察者的生命周期處於非活躍狀態(如返回棧中的 Activity),則它不會接收任何 LiveData 事件。
不再需要手動處理生命周期
界面組件只是觀察相關數據,不會停止或恢復觀察。LiveData 將自動管理所有這些操作,因為它在觀察時可以感知相關的生命周期狀態變化。
數據始終保持最新狀態
如果生命周期變為非活躍狀態,它會在再次變為活躍狀態時接收最新的數據。例如,曾經在后台的 Activity 會在返回前台后立即接收最新的數據。
適當的配置更改
如果由於配置更改(如設備旋轉)而重新創建了 Activity 或 Fragment,它會立即接收最新的可用數據。
共享資源
您可以使用單一實例模式擴展 LiveData 對象以封裝系統服務,以便在應用中共享它們。LiveData 對象連接到系統服務一次,然后需要相應資源的任何觀察者只需觀察 LiveData 對象。有關詳情,請參閱擴展 LiveData。
實現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 訪問該列表,如下所示:

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);
       //觀察數據是否改變,改變就重寫
       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
優點:將setText()減少到一句
缺點:setOnClickListener出現過多代碼不好看

DataBinding

在buid.gradle開啟數據綁定:

之后重新構建項目sync
進入activity_main.xml中點擊

之后會多兩個標簽

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:將界面對象綁定到控制器的ActivityMainBinding對象中(可以調用bind.xml標簽名)
    ActivityMainBinding bind;//注意這個類的名字和你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:將屏幕數據和控件的xml綁定
        bind.setData1(myViewModel);//setData1是因為在xml那個數據的name自己設定的data1,所以這setData1也是不固定的
        //這句很重要,相當於之前設置的觀察者語句
        bind.setLifecycleOwner(this);

    }
}

ui:

功能:顯示點擊按鈕次數
優點:控制器代碼減少,分工更明確
activity_main.xml變化:這個寫法有點像javaweb的模板引擎thymeleaf



最后的
thymeleaf相關圖:

相關變化圖:
最原始的,通過findViewById將單個組件的引用和控制器來連接起來,數據顯示和變化都在控制器中

加入ViewModel之后將頁面數據(UIData)單獨提出來封裝

加入LiveData,將之前提出來的UIData換為LiveData類型的,因為它滿足觀察者類型,可以減少setText的書寫,降低代碼耦合性

加入DataBinding將數據操作綁定到相關界面的xml文件中,減少控制器的代碼量,分工更明確了
ui

參考鏈接

[android開發者官網](https://developer.android.google.cn/jetpack) [視頻](https://www.bilibili.com/video/av50954019?p=11)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM