美文网首页
Databinding

Databinding

作者: code希必地 | 来源:发表于2020-11-26 11:17 被阅读0次

1、简介

MVVM将 MVP中的Presenter改为ViewModel,类似于MVP模式,不同的是ViewModel跟View和Model进行双向绑定:当View发生改变时,ViewModel通知Model进行更新数据;同理Model数据更新后,ViewModel通知View更新。MVVM的结构如下图:

MVVM.png
MVVM是一种模式,而DataBinding是一个框架,它是实现MVVM模式的一个工具,而MVVM模式中的ViewModel和View可以通过DataBinding来实现双向绑定。

2、DataBinding的使用

在DataBinding之前,我们需要大量的findViewById()、setText()和setOnClickListener()代码。通过Databinding,我们可以以在布局文件中进行逻辑和视图的绑定,这样就可以省略大量的模板代码。要想使用DataBinding需要在Module的gradle中进行如下配置:

android{
 dataBinding {
        enabled true
    }
}

2.1、DataBinding的基础使用

首先创建一个Model类

data class Student(val name: String, val age: Int)

下面编写xml文件

<?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>
        <variable
            name="student"
            type="com.example.mvvmtest.bean.Student" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{student.name}" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(student.age)}" />
    </LinearLayout>
</layout>

根节点是一个layoutlayout中包含了data节点和传统的视图,在data中定义了variable节点,name表示变量的名称,type表示变量的类型。variable中定义的每一个变量,都会在DataBinding辅助类中生成getter和setter方法,我们可以使用DataBinding辅助类对象调用响应的set方法进行赋值。接着使用@{student.name}@{String.valueOf(student.age)}给text进行赋值。最后在MainActivity中进行实体类和布局的绑定。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding =
            DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
        val stu = Student("肥肥", 300)
        binding.student = stu
    }
}

2.2、事件的处理

事件的处理有两种方式:

  • 方式一:
    在xml中定义一个Button
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
   <!--..... -->
        <Button
            android:layout_width="match_parent"
            android:layout_height="44dp"
            android:text="点击"
            android:id="@+id/btn_click"/>
    <!--..... -->
</layout>

在MainActivity中调用它

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding =
            DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
        //....
        binding.btnClick.setOnClickListener {
            "按钮被点击了".showToast(this)
        }
    }
}

btnClick就是id为btn_click的Button,当我们给控件每设定一个id,就会在binding的辅助类中生成一个响应的public final字段,以供调用。

  • 方式二
    在xml中定义一个名为mOnclickListener,类型为android.view.View.OnClickListener的变量,给Button的onClick属性赋值为@{mOnclickListener}
<?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>
        <variable
            name="mOnclickListener"
            type="android.view.View.OnClickListener" />
    </data>

    ....
        <Button
            android:layout_width="match_parent"
            android:layout_height="44dp"
            android:text="点击"
            android:onClick="@{mOnclickListener}"/>
   ....
</layout>

在MainActivity中调用如下:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding =
            DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
        binding.setMOnclickListener {
            "按钮被点击了".showToast(this)
        }
    }
}
  • 方式三
<?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>
        <variable
            name="viewModel"
            type="com.example.databindingmodule.MainViewModel" />

    </data>


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">

        <Button
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:onClick="@{v->viewModel.openActivity(v)}"
            android:text="打开新的页面" />

    </LinearLayout>

</layout>

这样在点击按钮的时候就能回调MainViewModel中的方法openActivity(v)

class MainViewModel { 
    fun openActivity(v:View) {
        weakContext?.get()?.let {
            val intent = Intent(it, JetpackActivity::class.java)
            it.startActivity(intent)
        }
    }
}

2.3、import的使用

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <import type="android.view.View.OnClickListener"/>
        <import type="com.example.mvvmtest.bean.Student"/>
        <variable
            name="student"
            type="Student" />

        <variable
            name="mOnclickListener"
            type="OnClickListener" />
    </data>
</layout>

2.4、变量的定义

上面我们学习了如何在XML中定义实体类,下面我们看下基本类型变量和集合如何在XML中定义。

<?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>
        <!--基本类型的定义-->
        <variable
            name="name"
            type="String" />

        <variable
            name="age"
            type="int" />

        <variable
            name="isMan"
            type="boolean" />
        <!--集合的定义-->
        <variable
            name="list"
            type="java.util.ArrayList&lt;String&gt;" />

        <variable
            name="map"
            type="java.util.HashMap&lt;String,String&gt;" />

        <variable
            name="arrays"
            type="String[]" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{name}" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(age)}" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(isMan)}" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{list.get(0)}" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{map.get(`key`)}" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{arrays[0]}" />

    </LinearLayout>
</layout>

在MainActivity中调用

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding =
            DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
        binding.name = "LILEI"
        binding.age = 100
        binding.isMan = true

        val list = ArrayList<String>()
        list.add("list one")
        binding.list = list

        val hashMap = HashMap<String, String>()
        hashMap["key"] = "map"
        binding.map = hashMap

        val array = arrayOf("数组")
        binding.arrays = array
    }
}

2.5、静态方法的使用

在布局文件中调用静态方法可以实现数据转换的效果,首先定义一个静态方法

class Utils {
    companion object {
        @JvmStatic
        fun getName(stu: Student) = stu.name
    }
}

然后在布局文件中引入我们使用的类

<?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>
        <variable
            name="student"
            type="com.example.mvvmtest.bean.Student" />
        <import type="com.example.mvvmtest.util.Utils" />

    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{Utils.getName(student)}" />
    </LinearLayout>
</layout>

在TextView中我们调用了静态方法@{Utils.getName(student)}设置文本,所以需要在Activity中传入Student对象

  val stu = Student("王晶1", 1400)
  binding.student = stu

2.6、支持表达式

在XML中支持如下表达式

  • 数学表达式:+-*/%
  • 字符串拼接:+
  • 逻辑表达式:&& ||
  • 位操作符:& | ^
  • 位移操作符:>> >>> <<
  • 比较操作符:== > < >= <=
  • instanceof
  • 强转 方法调用
  • 字段访问
  • 三元操作符:?:
    下面举个简单的例子
  <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{`Age is `+String.valueOf(student.age)}" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="显示与否"
            android:visibility="@{booleanValue?View.VISIBLE:View.GONE}" />

3、动态更新

前面学习的Databinding的例子中,如果实体类的内容发生了改变,那么UI界面是不会动态更新的。Databinding提供了三种动态更新机制,根据Model实体类的内容动态更新UI,分别是类(Observable)、字段(ObservableField)、集合类型(Observable容器类),下面我们逐一分析:

3.1、使用Observable

创建实体类继承BaseObservable来实现动态更新(Kotlin中不知到如何实现,以后学习到了再说

public class Student extends BaseObservable {
    private String name;
    private int age;

    @Bindable
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(BR.name);
    }

    @Bindable
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
       notifyPropertyChanged(BR.age);
    }
}

在getter方法上使用注解@Bindable,在setter中通知更新就可以了。其中BR是编译时生成的类,用@Bindable标记过的getter方法会在BR中生成一个相应的字段。在setter中调用notifyPropertyChanged(BR.age)通知BR.age这个字段数据发生变化并更新UI。我们在Activity中使用如下:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding =
            DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
        val stu = Student()
        stu.name = "王晶"
        stu.age = 120
        binding.student = stu

        binding.setMOnClickListener {
            when (it.id) {
                //更新Model中的数据,UI也会相应的更新
                R.id.btn_update-> stu.age = 100
            }
        }
}

3.2、使用ObservableField

除了使用继承BaseObservable来实现动态更新外,还可以使用基本数据类型对应的Observable类,比如ObservableInt、ObservableFloat、ObservableBoolean等。又或者使用基本数据类型和引用数据类型通用的ObservableField类,它们都继承自BaseObservable,现在以ObservableField类为例:

public class Teacher {
    private ObservableField<String> t_name =new ObservableField<String>();
    private ObservableField<Integer> t_age=new ObservableField<>();

    public ObservableField<String> getT_name() {
        return t_name;
    }

    public void setT_name(ObservableField<String> t_name) {
        this.t_name = t_name;
    }

    public ObservableField<Integer> getT_age() {
        return t_age;
    }

    public void setT_age(ObservableField<Integer> t_age) {
        this.t_age = t_age;
    }
}

然后与布局文件进行绑定

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable
            name="mOnClickListener"
            type="android.view.View.OnClickListener" />


        <variable
            name="teacher"
            type="com.example.mvvmtest.bean.Teacher" />

    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">

        <Button
            android:id="@+id/btn_update"
            android:layout_width="match_parent"
            android:layout_height="44dp"
            android:onClick="@{mOnClickListener}"
            android:text="更新数据"
            android:textAllCaps="false" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{teacher.t_name}" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(teacher.t_age)}" />

    </LinearLayout>
</layout>

最后在Activity中更新数据

  val teacher=Teacher()
        teacher.t_name.set("勺勺")
        teacher.t_age.set(23)
        binding.teacher=teacher

        binding.setMOnClickListener {
            when (it.id) {
                R.id.btn_update-> {
                    teacher.t_age.set(1000)
                }
            }
        }

3.3、使用Observable容器类

如果有多个Swordman类型的数据要更新,就需要使用Observable容器类ObservableArrayList和ObservableArrayMap,这时无需创建符合更新机制的Model实体类,只需要在代码中应用ObservableArrayList即可。代码如下:

data class Swordsman(var name:String,var level:String)
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding =
            DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
val swordsmanList=ObservableArrayList<Swordsman>()
        val swordsman1=Swordsman("张无忌","S")
        val swordsman2=Swordsman("周芷若","B")
        swordsmanList.add(swordsman1)
        swordsmanList.add(swordsman2)
        binding.swordmanList=swordsmanList
  binding.setMOnClickListener {
            when (it.id) {
                R.id.btn_update-> {
                    swordsman1.level="S++++"
                    //记得调用swordsmanList.add()否则不能更新
                    swordsmanList.add(swordsman1)
                }
            }
        }

然后绑定XML布局文件

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <import type="com.example.mvvmtest.bean.Swordsman"/>
        <variable
            name="swordmanList"
            type="androidx.databinding.ObservableArrayList&lt;Swordsman&gt;" />
    </data>
<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{swordmanList.get(0).level}" />
    </LinearLayout>
</layout>

4、双向绑定

从MVVM模式的角度来讲,双向绑定就是Model和View通过ViewModel进行双向动态更新。前面讲了Model变化,UI会动态更新,反过来如果View变化,Model该如何自动更新呢?下面举个简单的例子来实现双向绑定,双向绑定的前提是需要结合动态更新机制
使用ObservableField创建Model实体类并实现动态更新机制

public class Man {
   public ObservableField<String> name=new ObservableField<>();

    public ObservableField<String> getName() {
        return name;
    }

    public void setName(ObservableField<String> name) {
        this.name = name;
    }
}

然后在xml进行视图绑定

<?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="man"
            type="com.example.mvvmtest.bean.Man" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:text="@{man.name}" />

        <EditText
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:layout_marginTop="20dp"
            android:text="@={man.name}" />

        <Button
            android:id="@+id/btn_reset"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:text="重置"
            android:layout_marginTop="20dp" />
    </LinearLayout>
</layout>

在布局文件中定义EditText来改变Man中的name字段,关键是将@{man.name}改成了@={man.name},定义TextView来动态显示Man中name的动态变化。
在Activity中完成调用

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityBindingsBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_bindings);
        Man man=new Man();
        man.name.set("任我行");
        viewDataBinding.setMan(man);
        viewDataBinding.btnReset.setOnClickListener(new View.OnClickListener(){

            @Override
            public void onClick(View view) {
                man.getName().set("田玉琴");
            }
        });
    }

运行程序你会发现,当EditText中的文字发生变化时,TextView中的内容也会做相应的变化,当通过按钮进行重置Man中的name时EditText和Text也会变化,这样就实现了一个双向绑定。

5、常用注解

5.1、@BindAdapter

@BindAdapter注解的作用是扩展属性。在xml中的控件属性不能满足时 ,可以使用此注解进行属性的扩展。比如:我们在给ImageView加载网络图片时,ImageView原有的属性是无法满足的。下面举例说明如何使用注解进行属性的扩展。

  • 首先创建一个名为ViewBindingAdapter的文件,在其中定义一个顶层方法
@BindingAdapter("imgUrl")
fun loadPicForImgView(iv:ImageView,url:String){
    Glide.with(view).load(url).into(iv)
}

然后在xml布局中增加一个ImageView控件

<ImageView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    imgUrl="@{student.imgUrl}"/>

注意:@BindingAdapter注解修饰的方法必须是静态方法,而且方法中的第一个参数必须是需扩展属性的空间,所以这里传入了ImageView。
@BindingAdapter注解中传入的有两个参数:

  • 第一个参数是字符串数组,代表的要扩展的属性,如果只需扩展一个属性,那么只需传一个字符串即可。如果需要扩展多个属性,则传入一个字符串数组,此时就需要第二个参数了。
  • 第二个参数是一个boolean类型的,为true则表示第一个参数中所有属性都必须在控件中设置,否则则不需要。
// 当为false时
@BindingAdapter(value = ["imgUrl", "bgRes"], requireAll = false)
fun setImgUrl(view: ImageView, url: String, res: Int) {
    Glide.with(view).load(url).into(view)
    view.setBackgroundResource(res)
}
<!-- xml文件代码 -->
<ImageView
    android:layout_width="80dp"
    android:layout_height="80dp"
    imgUrl="@{viewModel.imgUrl}"/>

// 当为true时
@BindingAdapter(value = ["imgUrl", "bgRes"], requireAll = true)
fun setImgUrl(view: ImageView, url: String, res: Int) {
    Glide.with(view).load(url).into(view)
    view.setBackgroundResource(res)
}
<!-- xml文件代码 -->
<!-- 这段请放在data标签中 -->
<import type="top.cyixlq.test.R"/>

<ImageView
    android:layout_width="80dp"
    android:layout_height="80dp"
    imgUrl="@{viewModel.imgUrl}"
    bgRes="@{R.mipmap.ic_launcher}"/>

5.2、@BindingConversion

将不符合控件属性的值的类型转换成符合的类型。比如Text的text需要的是String类型的,但是设置给text的却是Long型的,这时候就可以使用注解进行转换了。具体使用如下:
首先创建一个静态方法,并用注解修饰

@SuppressLint("SimpleDateFormat")
@BindingConversion
fun convertIntToString(value: Long): String {
    val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    return formatter.format(value)
}

然后在XML文件中TextView的text传入Long型

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{System.currentTimeMillis()}"/>

这样就能将Long型转换成String类型了。但是需要注意的是,一旦使用@BindingConversion注解,那么所有需要Long型转换成String类型的控件,都会生效,这样使用起来就不太灵活,我们完全可以使用静态方法来代替。

5.3、@InverseMethod

在开发中我们遇到某个数字或字符串代表某种状态。比如1代表男,2代表女,在用户选择好之后,在回传到后台时还需要进行手动转换,如果不想手动转换就可以使用这个注解。下面看下具体的使用:

// 这个注解参数为反转的方法名,意味着一个这个注解需要两个方法才能完成
@InverseMethod("sexToNum")
fun numToSex(num: Int): String {
    return when (num) {
        0 -> "女"
        1 -> "男"
        else -> "未知性别"
    }
}

fun sexToNum(sex: String): Int {
    return when(sex) {
        "女" ->0
        "男" -> 1
        else -> 2
    }
}

这个注解主要用于双向绑定时使用,所以需要定义两个方法,需要有来回转换的两个方法。而且要转换的数据需要具有动态更新的能力。
在布局文件中添加一个TextView和一个EditText,TextView用来观察num这个值的变化,EditText用来展示转换好之后的数据:

<!-- 这里别忘了导入,导入了下面的EditText才能用这个类 -->
<import type="top.cyixlq.test.ViewInverseMethodsKt"/>

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{String.valueOf(viewModel.num)}"/>
<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@={ViewInverseMethodsKt.numToSex(viewModel.num)}"/>

这时候编译运行,EditText直接显示了男,如果我们删除男,EditText立马显示了未知性别。因为空字符串会对应到sexToNum中的else,所以num的值瞬间变成2,而2又对应numToSex中的else,所以EditText就会显示未知性别。当我们把未知性别几个字全部删除,输入1,或者2也好,num都是2,因为字符串-"1",字符串-"2"都是对应sexToNum方法中的else。但是如果我们在输入框中输入男,num就变成1了,输入女num就变成0了。

6、在RecyclerView中的使用

DataBinding除了在在Activity中使用,还可以在RecyclerView中使用。具体使用如下:
首先创建Activity的布局文件

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recy_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</layout>

给RecyclerView设定了id,这样就可以在Data Binding来使用RecyclerView的控件了。接着定义Item的布局文件

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="student"
            type="com.example.jetpacktest.Student" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="120dp"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:gravity="center"
            android:text="@{student.name}" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:gravity="center"
            android:text="@{String.valueOf(student.age)}" />
    </LinearLayout>
</layout>

下面看下Adapter

class MyAdapter(val context: Context, var mData: ArrayList<Student>) :
    RecyclerView.Adapter<MyAdapter.MyHolder>() {


    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyHolder {
        val binding = DataBindingUtil.inflate<ItemListBinding>(
            LayoutInflater.from(context),
            R.layout.item_list,
            parent,
            false
        )
        return MyHolder(binding)
    }

    override fun onBindViewHolder(holder: MyHolder, position: Int) {
        holder.binding.student = mData[position]
        holder.itemView.setOnClickListener {
            mData[position].name = "张无忌${Random.nextInt(1, 1000)}"
            mData[position].age = Random.nextInt(1, 1000)
        }
    }

    override fun getItemCount(): Int = mData.size

    inner class MyHolder(val binding: ItemListBinding) : RecyclerView.ViewHolder(binding.root)
}

和普通Adapter使用的不同的是:创建ViewHolder时并没有传入View而是传入了ItemListBinding,在ViewHolder中我们没有通过findViewById查找相应的控件,而是通过返回ItemListBinding来实现控件的查找。
接着看下在Activity中的使用:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding =
            DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)

        binding.recyList.layoutManager = LinearLayoutManager(this)
        binding.recyList.adapter = MyAdapter(this,initDataList())
    }

    private fun initDataList(): ArrayList<Student> {
        val mDataList = ArrayList<Student>()
        for (i in 0 until 50) {
            val stu = Student("姓名$i", i)
            mDataList.add(stu)
        }
        return mDataList
    }
}

到此为止MVVM的支持库Data Binding就讲完了。

相关文章

  • MVVM

    DataBinding基础用法 DataBinding入门 Android数据绑定框架DataBinding,堪称...

  • DataBinding

    dataBinding的使用 一、databinding的配置方法 二、databinding的基本使用 三、da...

  • DataBinding添加监听

    这章介绍DataBinding添加监听。如果不了解DataBinding的话,请查看[DataBinding的简单...

  • DataBinding系列(二):DataBinding的基本用

    在上一章 DataBinding系列(一):DataBinding初认识,我们已经认识了DataBinding,并...

  • Android MVVM模式的理解

    在之前的系列文章DataBinding系列(一):DataBinding初认识中讲过了关于DataBinding用...

  • dataBinding原理

    dataBinding如何绑定View? dataBinding如何修改View?

  • Android DataBinding

    Android DataBinding DataBinding 文档[https://developer.andr...

  • android databinding 初体验

    这是一篇databinding使用初体验,文章主要介绍了databinding使用,如何使用DataBinding...

  • Data Binding基础用法

    1.DataBinding配置2.DataBinding的使用3.UI/事件绑定 1.DataBinding配置 ...

  • dataBinding

    DataBinding DataBinding DataBinding是谷歌发布的一种数据绑定的框架,能够省去fi...

网友评论

      本文标题:Databinding

      本文链接:https://www.haomeiwen.com/subject/hgpoiktx.html