• 【Android】DataBinding 最全使用解析


    一、DataBinding 概述

    DataBinding 是谷歌官方在2015谷歌I/O大会发布的一个数据绑定框架,是 MVVM 模式在 Android 上的一种实现,用于降低布局和逻辑的耦合性,使代码逻辑更加清晰。DataBinding 能够省去我们一直以来的 findViewById() 步骤,大量减少 Activity 内的代码,DataBinding 也是Android Jetpack中非常重要的一部分。

    在这里插入图片描述

    二、基本用法

    2.1 使用入门

    DataBinding 在android工程中默认是关闭的,需要在build.gradle文件中添加一下配置开启DataBinding

    android {
            ...
            dataBinding {
                enabled = true
            }
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    找到需要开启DataBinding 的Activity对应的布局文件,将鼠标放到布局文件的第一行选择Convert to data binding layout自动转换。即可将布局文件改造成DataBinding 格式。
    在这里插入图片描述

    
    <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:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Hello World!"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />
    
        androidx.constraintlayout.widget.ConstraintLayout>
    layout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    Activity对应的布局文件自动生成以布局文件名字开头Binding结尾的Java类,如下代码所示

    public class MainActivity extends AppCompatActivity {
        ActivityMainBinding activityMainBinding;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            activityMainBinding = DataBindingUtil.setContentView(this,R.layout.activity_main);
            
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    RecyclerView中使用DataBinding

    
        public class  MyAdatper extends RecyclerView.Adapter<MyViewHolder>{
    
            @NonNull
            @Override
            public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
                ChatitemBinding chatitemBinding =
                        DataBindingUtil.inflate(LayoutInflater.from(MainActivity.this),R.layout.chatitem,parent,false);
                MyViewHolder myViewHolder = new MyViewHolder(chatitemBinding.getRoot());
                myViewHolder.chatitemBinding = chatitemBinding;
                return myViewHolder;
            }
    
            @Override
            public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
                holder.chatitemBinding.setItem(chatlist.get(position));
            }
    
            @Override
            public int getItemCount() {
                return chatlist.size();
            }
        }
    
    
    
        public class MyViewHolder extends RecyclerView.ViewHolder{
            ChatitemBinding chatitemBinding;
            public MyViewHolder(@NonNull View itemView) {
                super(itemView);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    Fragment 中使用DataBinding

    public class FirstFragment extends Fragment {
    
        private FragmentFirstBinding binding;
    
        @Override
        public View onCreateView(
                LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState    ) {
    
            binding = FragmentFirstBinding.inflate(inflater, container, false);
            return binding.getRoot();
    
        }
    
    
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2.2 布局和绑定表达式

    要想实现数据绑定,需要在布局文件的data节点中定义variable节点,节点的name属性代表变量名字,type属性代表变量类型
    在控件的属性中通过@{}表达式把声明出来的数据对象设置给对应的 控件属性,在表达式语言中还可以使用以下运算符和关键字:

    • 算术运算符+ - / * %
    • 字符串连接运算符+
    • 逻辑运算符&& ||
    • instanceof
    • 三元运算符?:
    
    <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="content"
                type="String" />
            <variable
                name="enabled"
                type="boolean" />
            <variable
                name="person"
                type="com.example.databinding.Person" />
    
        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:text='@{enabled ? "" :""}'
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />
    
            <TextView
                android:id="@+id/textView2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="13dp"
                android:layout_marginEnd="20dp"
                android:text="@{person.name}"
                app:layout_constraintEnd_toEndOf="@+id/textView"
                app:layout_constraintTop_toBottomOf="@+id/textView" />
    
            <TextView
                android:id="@+id/textView3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="114dp"
                android:text='@{"test"+person.age}'
                app:layout_constraintBottom_toTopOf="@+id/textView"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent" />
            <TextView
                android:id="@+id/textView4"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="62dp"
                android:text="@{content}"
                app:layout_constraintBottom_toTopOf="@+id/textView3"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent" />
        androidx.constraintlayout.widget.ConstraintLayout>
    layout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    activity中使用activityMainBinding对象的setContentView方法来设置绑定

    public class MainActivity extends AppCompatActivity {
        ActivityMainBinding activityMainBinding;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            activityMainBinding = DataBindingUtil.setContentView(this,R.layout.activity_main);
            Person person = new Person();
            person.age = 20;
            person.name = "test";
            String content = "content";
            boolean enable = false;
            activityMainBinding.setPerson(person);
            activityMainBinding.setContent(content);
            activityMainBinding.setEnabled(enable);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2.3 事件绑定

    DataBinding不仅可以将值绑定到控件上,还可以将事件绑定到控件上。
    首先在activity中定义一个类,在该类中定义一个参数为View的方法,并将该类用activityMainBinding对象的setContentView方法来设置绑定。

    public class MainActivity extends AppCompatActivity {
        ActivityMainBinding activityMainBinding;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            activityMainBinding = DataBindingUtil.setContentView(this,R.layout.activity_main);
             activityMainBinding.setPresenter(new Presenter());
        }
    
        public  class Presenter{
            public void onClick(View view){
                Log.i("Presenter","onClick");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在布局文件中,data节点设置该点击事件对象,然后在控件的android:onClick="@{presenter.onClick}"属性中设置绑定即可。

    
    <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="presenter"
                type="com.example.databinding.MainActivity.Presenter" />
        data>
        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".MainActivity">
             <Button
                android:id="@+id/button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginEnd="147dp"
                android:layout_marginBottom="75dp"
                android:text="Button"
                android:onClick="@{presenter.onClick}"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent" />
        androidx.constraintlayout.widget.ConstraintLayout>
    layout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    带参数的事件绑定
    将点击类的中定义的方法onClick参数改成需要点击回传的参数,在点击事件控件中设置android:onClick="@{()->presenter.onClick(person)}"即可将布局文件的变量中通过点击事件回传。

    public  class Presenter{
        public void onClick(Person person){
            Log.i("Presenter","onClick" + person.name);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="147dp"
        android:layout_marginBottom="75dp"
        android:text="Button"
        android:onClick="@{()->presenter.onClick(person)}"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.4 单向绑定

    上面的对象绑定,当对象的值改变并不会引起页面控件的自动更新,要想实现数据变化后视图也跟着自动变化可以使用以下两种方法:
    方法1:继承BaseObservable类,并将对象的属性添加set和get方法

    public class Person extends BaseObservable {
        public int age;
        public String name;
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
            notifyChange();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    当对象给相应的属性赋值后,页面控件绑定的值即可实现自动刷新

    public  class Presenter{
        public void onClick(Person person){
            person.setName( "new test");
            person.setAge( 30);
            Log.i("Presenter","onClick" + person.name);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    如果只想属性的部分值更新,在该属性的get方法上添加 @Bindable即可

    import androidx.databinding.BaseObservable;
    import androidx.databinding.Bindable;
    
    public class Person extends BaseObservable {
        public int age;
        public String name;
    
        @Bindable
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
        @Bindable
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
            notifyPropertyChanged(BR.name);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    方法2

    该类的属性用ObservableField封装同样的也可以实现单向绑定

    public class Person   {
        public ObservableField<Integer> age = new ObservableField<>();
        public ObservableField<String> name = new ObservableField<>();
    }
    
    • 1
    • 2
    • 3
    • 4

    也可以用一下类型

    • BaseObservable,
    • ObservableBoolean,
    • ObservableByte,
    • ObservableChar,
    • ObservableDouble,
    • ObservableField,
    • ObservableFloat,
    • ObservableInt,
    • ObservableLong,
    • ObservableParcelable,
    • ObservableShort,

    该对象的属性会自带set和get方法,调用set方法即可实现页面控件绑定的数据自动刷新

     public  class Presenter{
            public void onClick(Person person){
                person.name.set( "new test");
                person.age.set( 30);
                Log.i("Presenter","onClick" + person.name);
                content.set("new content");
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.5 双向绑定

    对于输入控件,使用@={}表达式即可实现页面和绑定的值双向自动刷新

    <EditText
        android:id="@+id/editTextTextPersonName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="85dp"
        android:layout_marginBottom="7dp"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="@={content}"
        app:layout_constraintBottom_toBottomOf="@+id/textView3"
        app:layout_constraintEnd_toEndOf="parent" />
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    完整代码如下所示

    
    public class MainActivity extends AppCompatActivity {
        ActivityMainBinding activityMainBinding;
        ObservableField<String> content;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            activityMainBinding = DataBindingUtil.setContentView(this,R.layout.activity_main);
            content = new ObservableField<>("content ");
            activityMainBinding.setContent(content);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    
    <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="content"
                type="androidx.databinding.ObservableField<String>" />
        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:text='@{content}'
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />
            <EditText
                android:id="@+id/editTextTextPersonName"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="44dp"
                android:layout_marginEnd="84dp"
                android:ems="10"
                android:inputType="textPersonName"
                android:text="@={content}"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/textView" />
        androidx.constraintlayout.widget.ConstraintLayout>
    layout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    三、高级用法

    BindingAdapter

    DataBinding支持在普通方法上添加@注解来添加自定义控件属性,该方法需满足以下条件:

    • 修饰方法, 要求方法必须public static
    • 方法参数第一个要求必须是View
    • 方法名不作要求
        @BindingAdapter("imageurl")
        public static void bindImageUrl(ImageView view,String url){
            Glide.with(view)
                    .load(url)
                    .into(view);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    使用方法如下:

            <ImageView
                android:id="@+id/imageView"
                android:layout_width="150dp"
                android:layout_height="150dp"
                app:imageurl="@{item.head}"
         />
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    Maven了解&运用配置
    2023年中国少儿在线英语教育分类、市场规模及发展趋势分析[图]
    python如何与前端交互
    2022年java开发跑路-真实面试题
    SQLServer 数字加千分位 用FORMAT函数强转不管多大位数
    八臂聚乙二醇硅烷 8ARM-PEG-Silane 8ARM-PEG-Si 八臂PEG硅 的描述
    react-starter脚手架搭建过程
    2022-09-09 Unity InputSystem2——代码检测输入
    网络安全笔记-信息安全工程师与网络安全工程师考试大纲(附:Web安全大纲)
    简单实现Springcloud跨项目相互调用
  • 原文地址:https://blog.csdn.net/huweiliyi/article/details/126443542