Android Jetpack開發 —— ViewModel、LiveData、DataBinding簡單使用

前言:

Jetpack網上一搜全都有解釋,在這裏我就不介紹Jetpack了,直接給 ViewModel、LiveData、DataBinding上例子。

注:本文基於AndroidX的項目,本人自己理解的意思做的講解,有不對或疑惑的地方歡迎評論留言一起學習探討。

 

一、ViewModel:

1、功能:屏幕旋轉或者字號改變的時候該Activity數據不會丟失。

2、做法:寫一個類繼承ViewModel:

public class MyViewModel extends ViewModel {

    private int number;

    public int getNumber() {
        return number;
    }

    public void addNumber(int number) {
        this.number += number;
    }
}

3、Activity中:

public class MainActivity extends AppCompatActivity {

    private MyViewModel viewModel ;
    private TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = findViewById(R.id.textView);
        viewModel = new ViewModelProvider(this,ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication())).get(MyViewModel.class);
        tv.setText(String.valueOf(viewModel.getNumber()));
        
        findViewById(R.id.button).setOnClickListener(v -> {
            //可以給個事件來點擊然後這個數值就加2
            viewModel.addNumber(2);
            tv.setText(String.valueOf(viewModel.getNumber()));
        });

此處需要注意,網上的教程甚至官網的教程給viewModel賦值的時候都是用的ViewModelProviders.of(this).get()的方法,但是這個方法已經淘汰了,所以得自己構建這樣一個函數,然後又會發現ViewModelProvider(this)這個構造函數並不存在,只有兩個參數的構造函數,ctrl+鼠標移到ViewModelProvider上面,可以發現需要一個傳一個工廠參數,所以就有了上面這個寫法。

 

 

二、LiveData:

1、作用:顧名思義,實時數據,就是數據發生改變的時候,它能自己去修改UI上面上的數據。比如上面我們點擊按鈕之後還需要手動去給這個textView重新setText。有了這個LiveData,我們就不用每次都給它重新設置值了。

2、做法:在上面這個MyViewModel中做修改:

public class MyViewModel extends ViewModel {

    private MutableLiveData<Integer> number;

    public MutableLiveData<Integer> getNumber() {
        if (number == null) {
            number = new MutableLiveData<>();
            number.setValue(0);
        }
        return number;
    }

    public void addNumber(int number) {
        this.number.setValue(getNumber().getValue() + number);
    }
}

注意:MutableLiveData<這裏可以是其他bean對象,但是不能是view或者帶Context的東西,因爲viewModel的生命週期比Activity或者Fragment長>

3、Activity中給這個數據添加監聽:

public class MainActivity extends AppCompatActivity {

    private MyViewModel viewModel ;
    private TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = findViewById(R.id.textView);
        viewModel = new ViewModelProvider(this,ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication())).get(MyViewModel.class);
        tv.setText(String.valueOf(viewModel.getNumber()));
        
        //這裏添加監聽
        viewModel.getNumber().observe(this, new Observer<Integer>() {
            @Override
            public void onChanged(Integer integer) {
                tv.setText(String.valueOf(integer));
            }
        });
        
        findViewById(R.id.button).setOnClickListener(v -> {
            viewModel.addNumber(2);
            //這裏去掉了tv的setText
        });
        
        //或者再有其他按鈕也同理只做加減不做賦值
        findViewById(R.id.button2).setOnClickListener(v -> {
            viewModel.addNumber(-2);
        });

 

三、DataBinding:

1、作用:數據綁定,有了它,就不用findviewbyid了,甚至你可以不用在Activity裏面做setText和setOnClickListener。

2、做法:

     2.1、app的build.gradle裏面添加一個聲明:

android {
    ......
    defaultConfig {
        ......
        //下面這個添加上
        dataBinding{
            enabled true
        }
    }
    ......
}

     2.2、layout裏面的activity_main裏面,鼠標移到<?xml version="1.0" encoding="utf-8"?>左邊,會有一個燈泡,點擊下來點擊有data binding字樣的那句話,就會得到一個layout的根標籤:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="22sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.259" />

        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/button1"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.498"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.44" />

        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/button2"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.498"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.629" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

3、這個layout生成了之後它會自動生成一個以這個layout名字命名的類,比如這裏是activity_main,就會生成一個ActivityMainBinding的類,然後我們在Activity中使用它:

public class MainActivity extends AppCompatActivity {

    private MyViewModel viewModel ;
    private ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
//        setContentView(R.layout.activity_main);
        //注意此處把上面這個設置界面的方式換成下面這個,並且賦值給binding
        binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
        //然後就可以直接用binding.控件id 來表示該控件。
              
        viewModel = new ViewModelProvider(this,ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication())).get(MyViewModel.class);
        viewModel.getNumber().observe(this, new Observer<Integer>() {
            @Override
            public void onChanged(Integer integer) {
                //binding.textView表示原先tv對象了
                binding.textView.setText(String.valueOf(integer));
            }
        });
        
        //binding.button代替原先button
        binding.button.setOnClickListener(v -> {
            viewModel.addNumber(2);
        });
        
        binding.button2.setOnClickListener(v -> {
            viewModel.addNumber(-2);
        });

    }

4、這只是初級形態,我們還有個高級一點的。第2步中生成了的layout中有一對標籤沒有使用,就是<data />標籤對。下面我們來使用:

4.1、把viewModel對象搬移到layout的data標籤中:

<data>
    <variable
        name="viewModel"
        type="com.xaehu.jetpackstudy.MyViewModel" />

</data>

4.2、把setText和setOnClickListener搬到layout中:

<TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{String.valueOf(viewModel.number)}"/>

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button1"
        android:onClick="@{v -> viewModel.addNumber(2)}" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button2"
        android:onClick="@{v -> viewModel.addNumber(-2)}"/>

可以看到,格式是“@{}”的形式,裏面就是java代碼或者landau表達式。

 

4.3、然後修改Activity中代碼,可以說是簡潔到飛起了:

public class MainActivity extends AppCompatActivity {

    private MyViewModel viewModel ;
    private ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
        viewModel = new ViewModelProvider(this,ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication())).get(MyViewModel.class);
        binding.setViewModel(viewModel); //給layout設置data標籤的值
        binding.setLifecycleOwner(this); //這句不能漏,否則不會生效
   }

 

以上就是對ViewModel、LiveData、DataBinding的簡單使用。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章