Android_Databinding使用整理

自从使用android databinding之后,个人觉得还是很有必要掌握,相比于传统方式,android databinding的优势有如下:

  • 解决了数据直接去绑定ui
  • 解决ui可以直接绑定数据
  • 适用于MVVM框架
  • 提高了开发效率,减少了Activity、Fragment、View、Adapter等刷新的代码
  • 通过自定义属性,可以封装自己的布局代码

使用:

在app对应的model中build.gradle加上这句:

 

android {
    ....
    dataBinding {
        enabled = true
    }
}

实体在xml中使用:

 

<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="user"
            type="com.single.androiddatabing.bean.User" />
    </data>

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.single.androiddatabing.MainActivity">

        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:text="@{user.name}"
            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_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:text="@{String.valueOf(user.age)}"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/textView" />
    </android.support.constraint.ConstraintLayout>
</layout>

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
    ActivityMainBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
    User user = new User();
    user.age = 12;
    user.name = "zhangsan";
    viewDataBinding.setUser(user);
}

xml中通过layout根标签去添加布局,然后在data标签中定义好实体,在view中使用实体的时候用@{}来获取实体的数据,在代码中就会动态生成一个ActivityMainBinding类,代码中的setUser就是通过xml布局中name来生成的方法。

xml中import关键字使用:

 

<?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="user"
            type="com.single.androiddatabing.bean.User" />

        <import type="android.view.View" />
    </data>

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.single.androiddatabing.MainActivity">

        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:text="@{user.name}"
            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_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:text="@{String.valueOf(user.age)}"
            android:visibility="@{user.age>10?View.VISIBLE:View.GONE}"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/textView" />

    </android.support.constraint.ConstraintLayout>
</layout>

上面的例子中判断age>10才会显示,否则不显示。显示的时候,导入了View这个类,在第一个例子中,其实本应该导入String类型的,但是在dataBinding中除了基本类型不导入外,其余的都需要导入,其实这里还可以判断textColor、字体大小等等,这里就不一一举例了,大家在实际项目中慢慢使用、体会。

上面的例子中,导入的是系统提供的View类,dataBinding也支持自己写的类导入,下面写个简单的例子:

 

package com.single.androiddatabing.utils;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Created by xiangcheng on 18/12/28.
 */

public class FormatUtils {
    //定义了一个简单的格式化时间的方法
    public static String formatTime(Date date) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");
        return simpleDateFormat.format(date);
    }
}
布局添加import
<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="date"
            type="java.util.Date" />

        <import type="com.single.androiddatabing.utils.FormatUtils" />
    </data>

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.single.androiddatabing.MainActivity">

        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:text="@{FormatUtils.formatTime(date)}"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </android.support.constraint.ConstraintLayout>
</layout>

上面自定义工具类的方式看到了没,定义好工具类,直接调他们的方法,记得不要忘记在代码中调用:

 

ActivityImport1Binding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_import1);
viewDataBinding.setDate(new Date());

onClick事件使用lambda方式

  • 双冒号形式调用:

 

public class OnclickEvent {
    public void onClickFriend(View view) {
        if (view.getId() == R.id.textView) {
            Log.d("TAG", "点击了");
            Toast.makeText(view.getContext(), "button1被点击了", Toast.LENGTH_LONG).show();
        } else if (view.getId() == R.id.button) {
            Log.d("TAG", "点击了");
            Toast.makeText(view.getContext(), "button2被点击了", Toast.LENGTH_LONG).show();
        }
    }
}

布局代码:
<?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="onclickEvent"
            type="com.single.androiddatabing.event.OnclickEvent" />
    </data>

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.single.androiddatabing.MainActivity">

        <Button
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:onClick="@{onclickEvent::onClickFriend}"
            android:text="button1"
            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_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:onClick="@{onclickEvent::onClickFriend}"
            android:text="Button2"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/textView" />

    </android.support.constraint.ConstraintLayout>
</layout>

不要忘记在代码中设置onclickEvent:

 

ActivityOnclick1Binding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_onclick1);
viewDataBinding.setOnclickEvent(new OnclickEvent());

上面形式设置onclickEvent灵活性不是很高,个人不是很喜欢这种方式,下面再介绍一种。

  • lambda形式

 

public class OnclickEvent {
    public void runTask(Task task) {
        task.run();
    }

    public void runTask(View view, Task task) {
        Toast.makeText(view.getContext(), "执行了传view的runTask", Toast.LENGTH_SHORT).show();
        task.run();
    }

    public void runTask(View view, Task task, boolean isRun) {
        Toast.makeText(view.getContext(), "执行了传view的runTask", Toast.LENGTH_SHORT).show();
        if (!isRun) {
            task.run();
        }
    }

    public static class Task implements Runnable {
        @Override
        public void run() {
            Log.d("TASK", "怎么就执行了Task了呢");
        }
    }
}
xml代码:
<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="onclickEvent"
            type="com.single.androiddatabing.event.OnclickEvent" />

        <variable
            name="task"
            type="com.single.androiddatabing.event.OnclickEvent.Task" />
    </data>

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.single.androiddatabing.MainActivity">

        <Button
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:onClick="@{()->onclickEvent.runTask(task)}"
            android:text="button1"
            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_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:onClick="@{(view)->onclickEvent.runTask(view,task)}"
            android:text="Button2"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/textView" />

        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:onClick="@{(view)->onclickEvent.runTask(view,task,false)}"
            android:text="Button3"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/button" />

    </android.support.constraint.ConstraintLayout>
</layout>

上面例子中三个button分别传了各自的参数,如果要指明view的话,需要在前面的括号中说明,接下来不要忘记在代码中去设置onclickEventtask:

 

ActivityOnclick2Binding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_onclick2);
viewDataBinding.setOnclickEvent(new OnclickEvent());
viewDataBinding.setTask(new OnclickEvent.Task());

还有种方式也可以设置onClick,这种的话就比较单一了,其实不建议这种方式,耦合性不高:

 

<variable
    name="buttonClick"
    type="android.view.View.OnClickListener" />
<Button
    android:id="@+id/button3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:onClick="@{buttonClick}"
    android:text="Button4"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/button2" />
//activity中代码
viewDataBinding.setButtonClick(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        //todo
    }
});

集合在xml中使用:

 

<import type="java.util.List" />
<import type="com.single.androiddatabing.bean.User" />
<variable
    name="userList"
    type="List&lt;User&gt;" />
<variable
    name="index"
    type="Integer" />

<TextView
    android:id="@+id/textView3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:text="@{userList.get(0).name}"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />
<TextView
    android:id="@+id/textView4"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:text="@{userList[index].name}"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/textView3" />

不要忘了需要在代码中设置index值和userList的值:

 

ActivityListBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_list);
List<User> users = new ArrayList<>();
User user = new User();
user.name = "王小二";
users.add(user);
User user1 = new User();
user1.name = "王小三";
users.add(user1);
viewDataBinding.setIndex(1);
viewDataBinding.setUserList(users);

map在xml中使用

其实跟list使用差不多,直接上结果:

 

<import type="java.util.Map" />
<import type="com.single.androiddatabing.bean.User" />
<variable
    name="userMap"
    type="Map&lt;String,User&gt;" />
<variable
    name="key"
    type="String" />

<TextView
    android:id="@+id/textView3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:text="@{userMap.get(key).name}"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

ActivityMapBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_map);
Map<String, User> users = new HashMap();
User user = new User();
user.name = "王小二";
users.put("1", user);
User user1 = new User();
user1.name = "王小三";
users.put("2", user1);
viewDataBinding.setKey("1");
viewDataBinding.setUserMap(users);

include操作

这里以map的例子来说明下如何使用,直接上代码:

 

<data>
    <import type="java.util.Map" />
    <import type="com.single.androiddatabing.bean.User" />
    <variable
        name="userMap"
        type="Map&lt;String,User&gt;" />
    <variable
        name="key"
        type="String" />
</data>
<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.single.androiddatabing.MainActivity">
    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="@{userMap.get(key).name}"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="123" />
    <include
        layout="@layout/layout_include"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/textView3"
        app:myUser='@{userMap["2"]}' />
</android.support.constraint.ConstraintLayout>

layout_include代码:
<data>
    <variable
        name="myUser"
        type="com.single.androiddatabing.bean.User" />
</data>
<android.support.constraint.ConstraintLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    tools:context="com.single.androiddatabing.MainActivity">
    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="@{myUser.name}"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

activity中的代码:
ActivityIncludeBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_include);
Map<String, User> users = new HashMap();
User user = new User();
user.name = "王小二";
users.put("1", user);
User user1 = new User();
user1.name = "王小三";
users.put("2", user1);
viewDataBinding.setKey("1");
viewDataBinding.setUserMap(users);

ViewStub使用

 

<data>
    <import type="java.util.Map" />
    <import type="com.single.androiddatabing.bean.User" />
    <variable
        name="userMap"
        type="Map&lt;String,User&gt;" />
    <variable
        name="key"
        type="String" />
</data>
<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.single.androiddatabing.MainActivity">
    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="@{userMap.get(key).name}"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="123" />
    <ViewStub
        android:id="@+id/view_stub"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout="@layout/layout_include"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/textView3" />
</android.support.constraint.ConstraintLayout>

activity中代码:
ActivityViewstubBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_viewstub);
Map<String, User> users = new HashMap();
User user = new User();
user.name = "王小二";
users.put("1", user);
User user1 = new User();
user1.name = "王小三";
users.put("2", user1);
viewDataBinding.setKey("1");
viewDataBinding.setUserMap(users);
viewDataBinding.viewStub.setOnInflateListener(new ViewStub.OnInflateListener() {
    @Override
    public void onInflate(ViewStub stub, View inflated) {
        LayoutIncludeBinding viewStubBinding = DataBindingUtil.bind(inflated);
        User user = new User(12, "谢后");
        viewStubBinding.setMyUser(user);
    }
});
if (!viewDataBinding.viewStub.isInflated()) {
    //viewDataBinding.viewStub获取的是ViewStubProxy
    viewDataBinding.viewStub.getViewStub().inflate();
}

这里可以看出来跟include的使用基本是一样的,主要看activity中代码。这种代码记下就行,完全是机械式代码咯。

自定义属性

上面的例子中都是单一的操作view的属性,下面介绍自定义属性的玩法:

 

public class ViewUtils {
    @BindingAdapter({"loadHighLight"})
    public static void loadLight(TextView textView, String text) {
        textView.setText(highlightMoney(text, text.substring(0, 2)));
    }
    public static SpannableStringBuilder highlightMoney(String text, String target) {
        SpannableStringBuilder spannable = new SpannableStringBuilder(text);
        CharacterStyle span = null;
        //用他们的小写来做判断
        if (!TextUtils.isEmpty(target)) {
            Pattern p = Pattern.compile(target.toLowerCase());
            Matcher m = p.matcher(text.toLowerCase());
            while (m.find()) {
                span = new ForegroundColorSpan(Color.parseColor("#FF801A"));// 需要重复!
                spannable.setSpan(span, m.start(), m.end(),
                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                StyleSpan styleSpan_B = new StyleSpan(Typeface.BOLD);
                spannable.setSpan(styleSpan_B, m.start(), m.end(),
                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
            return scannable;
        } else {
            return new SpannableStringBuilder(text);
        }
    }
}

上面写的自定义属性是高亮显示、加重的一个功能,所以说以后用到的地方直接调用该属性就可以了,下面看看如何使用该属性:

 

<data>
    <import type="java.util.List" />
    <import type="com.single.androiddatabing.bean.User" />
    <variable
        name="userList"
        type="List&lt;User&gt;" />
    <variable
        name="index"
        type="Integer" />
</data>
<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.single.androiddatabing.MainActivity">
    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:loadHighLight="@{userList.get(0).name}" />
    <TextView
        android:id="@+id/textView4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView3"
        app:loadHighLight="@{userList[index].name}" />
</android.support.constraint.ConstraintLayout>

看到xml里面了没,里面有app:loadHighLight该属性的使用。activity中就没什么好说的了:

 

ActivityHighlightBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_highlight);
List<User> users = new ArrayList<>();
User user = new User();
user.name = "90元/月";
users.add(user);
User user1 = new User();
user1.name = "80元/月";
users.add(user1);
viewDataBinding.setIndex(1);
viewDataBinding.setUserList(users);

 

双向绑定数据

上面的例子中都是数据发生变化的时候,不会主动去通知view发生变化,所以双向绑定数据能解决该问题,不用我们去关注view是不是发生了变化,下面介绍几种方式:

  • Observable Objects
    这种双向绑定是针对object来说的,直接让bean实体继承BaseObservable:

 

public class ObservableBean extends BaseObservable {
    private String firstName;
    private String lastName;
    public ObservableBean(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    @Bindable
    public String getFirstName() {
        return this.firstName;
    }
    @Bindable
    public String getLastName() {
        return this.lastName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
        notifyPropertyChanged(BR.firstName);
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
        notifyPropertyChanged(BR.lastName);
    }
}

提供set、get方法,并且在get方法上面加上@Bindable注解
xml如下:

 

<data>
    <variable
        name="observableBean"
        type="com.single.androiddatabing.bean.ObservableBean" />
    <variable
        name="myClick"
        type="android.view.View.OnClickListener" />
    <variable
        name="key"
        type="String" />
</data>
<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.single.androiddatabing.MainActivity">
    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="@{observableBean.firstName}"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <TextView
        android:id="@+id/textView6"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="@{observableBean.lastName}"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView3" />
    <Button
        android:id="@+id/button4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:onClick="@{myClick}"
        android:text="Button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView6" />
</android.support.constraint.ConstraintLayout>

activity中代码如下:

 

ActivityObservableObjectBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_observable_object);
final ObservableBean observableBean = new ObservableBean("张三", "李四");
viewDataBinding.setObservableBean(observableBean);
viewDataBinding.setMyClick(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        observableBean.setFirstName("zs");
        observableBean.setLastName("ls");
    }
});

上面的代码可以看出来点击按钮后实体的属性发生变化了,紧接着view的属性也发生了变化。

  • Observable Field
    这种方式的话,是针对object的属性而言的,用到的类是ObservableField了,把刚刚的例子改动如下:

 

public class ObservableFieldsUser {
    public ObservableField<String> firstName = new ObservableField<>();
    public ObservableField<String> lastName = new ObservableField<>();

    public ObservableFieldsUser(String firstName, String lastName) {
        this.firstName.set(firstName);
        this.lastName.set(lastName);
    }
}

xml的布局基本是一样的,activity代码如下:

 

ActivityObservableFieldBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_observable_field);
final ObservableFieldsUser observableBean = new ObservableFieldsUser("张三", "李四");
viewDataBinding.setObservableFieldsUser(observableBean);
viewDataBinding.setMyClick(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        observableBean.firstName.set("你是张三");
        observableBean.lastName.set("你是李四");
    }
});

系统自带的observable***还有很多,有如下类:

 

屏幕快照 2019-01-03 11.46.49.png

 

用法都是差不多,知道双向绑定是个怎么回事就ok了。

在RecyclerView中用Databinding重构自己的Adapter

 

public abstract class BaseRecyclerViewBingAdapter<T, B extends ViewDataBinding> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    protected List<T> list;
    protected B dataBing;
    private int variableId;
    protected Context context;

    public BaseRecyclerViewBingAdapter(Context context, List<T> list, int variableId) {
        this.context = context;
        this.list = list;
        this.variableId = variableId;
    }

    @Override
    public int getItemCount() {
        return list.size();
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //同样会根据布局生成一个相应的binding
        RecyclerView.ViewHolder viewHolder;
        dataBing = DataBindingUtil.inflate(
                LayoutInflater.from(context), getItemLayout(viewType), null, false);
        viewHolder = new BindingHolder<B>(dataBing.getRoot());
        ((BindingHolder) viewHolder).setBinding(dataBing);
        //这里getRoot会返回布局的根view
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        T t = list.get(position);
        ((BindingHolder) holder).getBinding().setVariable(variableId, t);
        ((BindingHolder) holder).getBinding().executePendingBindings();

        ((BindingHolder) holder).getBinding().getRoot().setOnClickListener(v -> {
            itemClick(t, position);
        });
        generateItem((B) ((BindingHolder) holder).getBinding(), t, position);
    }

    protected void generateItem(B dataBing, T t, int position) {

    }

    protected abstract int getItemLayout(int viewType);

    protected abstract void itemClick(T item, int position);

    public static class BindingHolder<B extends ViewDataBinding> extends RecyclerView.ViewHolder {

        //这里在holder里面,传入一个binding对象就ok了
        private B binding;

        public BindingHolder(View itemView) {
            super(itemView);
        }

        public B getBinding() {
            return binding;
        }

        public void setBinding(B binding) {
            this.binding = binding;
        }
    }

}

用法很简单,你只需要去继承该类,然后子类指明集合还有子类的布局就ok了。给个事例看下:

 

viewDataBinding.recycler.setAdapter(new BaseRecyclerViewBingAdapter<KewenItem, KewenSelectItemBinding>(this, sessions, BR.kewenItem) {
    @Override
    protected int getItemLayout(int viewType) {
        return R.layout.kewen_select_item;
    }
    @Override
    protected void itemClick(KewenItem item, int position) {
    }
});

item的布局:

 

<data>
    <variable
        name="kewenItem"
        type="com.single.androiddatabing.bean.KewenItem" />
</data>
<LinearLayout
    android:layout_width="100dp"
    android:layout_height="100dp">
    <TextView
        android:id="@+id/show_kewen"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:gravity="center"
        android:paddingLeft="@dimen/dp_10"
        android:paddingRight="@dimen/dp_10"
        android:textSize="@dimen/text_18"
        app:zhongri="@{kewenItem}"
        tools:text="大学孟子中庸学习" />
</LinearLayout>

item布局里面用到了一个app:zhongri属性,这里是自定义属性:

 

@BindingAdapter({"zhongri"})
public static void loadZhongriTextColor(TextView textView, KewenItem kewenItem) {
    textView.setTextColor(textView.getContext().getResources().getColor(kewenItem.textColor));
    textView.setBackground(textView.getContext().getResources().getDrawable(kewenItem.drawable));
    textView.setText(kewenItem.text);
}

最后效果图如下:

 

image.png

databinding在MvvM框架中如何使用

这里用到了google的lifecycle框架,因为平时比较喜欢用这个框架,因此也分享给大家学习学习:

 

public class UserModel extends AndroidViewModel {
    public ObservableField<User> userObservableField = new ObservableField<>();
    private final MediatorLiveData<User> userMediatorLiveData = new MediatorLiveData<>();

    public LiveData<User> getUser() {
        userMediatorLiveData.setValue(new User(11, "我是UserModel中构造出来的user"));
        return userMediatorLiveData;
    }

    public void setUserObservableField(User user) {
        userObservableField.set(user);
    }

    public UserModel(@NonNull Application application) {
        super(application);
    }

    /**
     * A creator is used to inject the product ID into the ViewModel
     * <p>
     * This creator is to showcase how to inject dependencies into ViewModels. It's not
     * actually necessary in this case, as the product ID can be passed in a public method.
     */
    public static class Factory extends ViewModelProvider.NewInstanceFactory {

        @NonNull
        private final Application mApplication;

        public Factory(@NonNull Application application) {
            mApplication = application;
        }

        @Override
        public <T extends ViewModel> T create(Class<T> modelClass) {
            //noinspection unchecked
            return (T) new UserModel(mApplication);
        }
    }
}

看到了双向绑定的影子了没,上面定义了ObservableField<User>变量,这里就是用来通知xml值发生变化了,要刷新ui了,因此可以看xml中如何搞定的:

 

<data>
    <variable
        name="userModel"
        type="com.single.androiddatabing.model.UserModel" />
</data>
<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.single.androiddatabing.MainActivity">
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="@{userModel.userObservableField.name}"
        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_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="@{String.valueOf(userModel.userObservableField.age)}"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView" />
</android.support.constraint.ConstraintLayout>

xml中也是挺简单的,直接定义好userModel,然后获取userModel中
userObservableField变量,最后展示bean的属性。activity中代码使用:

 

ActivityMvvmBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_mvvm);
UserModel.Factory factory = new UserModel.Factory(
        getApplication());
final UserModel model = ViewModelProviders.of(this, factory)
        .get(UserModel.class);
viewDataBinding.setUserModel(model);
model.getUser().observe(this, new Observer<User>() {
    @Override
    public void onChanged(@Nullable User user) {
        model.setUserObservableField(user);
    }
});

activity中代码也挺简单、明了的。有什么不明白的地方可以直接和我讨论,相信你会喜欢用mvvm框架的。

上面的例子代码都在这里:猛戳


 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值