Android Jetpack(三)Data Binding

        Data Binding 是谷歌官方发布的一个框架,发布于2015年的Google I/O大会,顾名思义即为数据绑定旨在减少Android开发中的大量模板代码(比如findViewById()),提高开发效率和维护效率

        Data Binding 能够省去我们一直以来的 findViewById() 步骤,大量减少 Activity 内的代码,开发时只需要关注数据(对象)即可,无需关心View的各种繁杂操作,例如各种更新 View 属性的 setter:setText(),setVisibility(),setEnabled() 或者 setOnClickListener() 等。

        Data Binding 通常与 ViewModelLiveData 组合使用来进行响应式UI设计。即:当底层数据被更新时,UI也会相应的自动更新。

        ViewModel + LiveData + Data Binding = 响应式UI

         

       Data Binding 也是 MVVM 模式在 Android 上的一种实现,用于降低布局和逻辑的耦合性,使代码逻辑更加清晰。MVVM 相对于 MVP,其实就是将 Presenter 层替换成了 ViewModel 层。数据能够单向或双向绑定到 layout 文件中,有助于防止内存泄漏,而且能自动进行空检测以避免空指针异常

        综上,Data Binding具有以下优点

  • 减少样板代码
  • 降低布局和逻辑的耦合性
  • 实现数据(对象)与View的双向绑定
  • 防止内存泄漏
  • 避免空指针异常

 

一、Data Binding 基本用法

1. 启用 Data Binding

        在 app 的 build.gradle 文件下加入以下代码,同步后就能引入对 Data Binding 的支持。

android {
    ...
    dataBinding {  //也可以添加在defaultConfig中
        enabled true
    }
}

2. 将布局文件转换成Data Binding Layout

        打开布局文件,选中根布局的 ViewGroup,按住 Alt + 回车键,点击 “Convert to data binding layout”,就可以生成 DataBinding 需要的布局规则。

        

        

        多出了一个 layout 标签将原布局包裹了起来,data 标签用于声明要用到的变量以及变量类型 。

 3. 创建所需要的 JavaBean,并在 data 标签中声明

<data>
    <variable
        name="userInfo"
        type="com.leavesc.databinding_demo.model.User" />
</data>

        如果 User 类型要多处用到,也可以直接将之 import 进来,这样就不用每次都指明整个包名路径了,而 java.lang.* 包中的类会被自动导入,所以可以直接使用。

<data>
    <import type="com.leavesc.databinding_demo.model.User"/>
    <variable
        name="userInfo"
        type="User"/>
</data>

4. 设置对象的属性值,使 TextView 显示相应的文本

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

    <data>
        <import type="com.leavesc.databinding_demo.model.User" />
        <variable
            name="userInfo"
            type="User" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="20dp"
        android:orientation="vertical"
        tools:context="com.leavesc.databinding_demo.Main2Activity">

        <TextView
            android:id="@+id/tv_userName"
            ···
            android:text="@{userInfo.name}" />

        <TextView
            ···
            android:text="@{userInfo.password}" />

    </LinearLayout>

</layout>

5. 在 Activity 中指定对应的布局文件,并将 Data Binding 绑定的对象注入

        在 Activity 中通过 DataBindingUtil 设置布局文件,省略原先 Activity 的 setContentView() 方法。

    private User user;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMain2Binding activityMain2Binding = DataBindingUtil.setContentView(this, R.layout.activity_main2);
        user = new User("leavesC", "123456");
        activityMain2Binding.setUserInfo(user);
    }

        以上就是 Data Binding 的基本用法,更多用法可参见 Android DataBinding 从入门到进阶

 

二、Data Binding 实现双向绑定

        使用 Data Binding 实现双向绑定的前提是需要结合 ViewModelLiveData 一起使用,即实现响应式UI,从而当数据更新时,UI也能够相对应的自动更新。

1. 启用 Data Binding

2. 编写符合业务逻辑的 ViewModel

public class MyViewModel2 extends ViewModel {
    private MutableLiveData<Integer> number;

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

    public void add() {
        number.setValue(number.getValue() + 1);
    }
}

3. 将布局文件转换成Data Binding Layout,并绑定 ViewModel

<?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>
        <variable
            name="data"
            type="software.baby.learnjetpack.MyViewModel2" />
    </data>

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

        <TextView
            android:id="@+id/textView"
            android:layout_width="15dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginBottom="8dp"
            android:text="@{String.valueOf(data.number)}"
            android:textSize="26sp"
            app:layout_constraintBottom_toTopOf="@+id/button"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:layout_marginBottom="296dp"
            android:onClick="@{()->data.add()}"
            android:text="@string/btn_add"
            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="1.0" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

4. 完善控制逻辑代码,实现双向绑定

public class Main3Activity extends AppCompatActivity {
    MyViewModel2 myViewModel;
    ActivityMain3Binding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(R.layout.activity_main3);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main3);
        myViewModel = ViewModelProviders.of(this).get(MyViewModel2.class);

        binding.setData(myViewModel);
        binding.setLifecycleOwner(this);  //不能省略,指定LifecycleOwner
    }
}

注意:如果我们在步骤3中,不去绑定对应的ViewModel,那么这时候数据的绑定是单向的。

<?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=".Main3Activity">

        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginTop="240dp"
            android:layout_marginEnd="8dp"
            android:text="@string/text_result"
            android:textSize="26sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="296dp"
            android:text="@string/btn_add"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.498"
            app:layout_constraintStart_toStartOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
public class Main3Activity extends AppCompatActivity {
    MyViewModel2 myViewModel;
    ActivityMain3Binding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(R.layout.activity_main3);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main3);
        myViewModel = ViewModelProviders.of(this).get(MyViewModel2.class);

        myViewModel.getNumber().observe(this, new Observer<Integer>() {
            @Override
            public void onChanged(Integer integer) {
                binding.textView.setText(String.valueOf(integer));
            }
        });
        binding.button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                myViewModel.add();
            }
        });
    }
}
发布了51 篇原创文章 · 获赞 53 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_34519487/article/details/104087956