注:主要参考精通 Android Data Binding,官方文档,感谢分享。
第一步:创建xml布局
创建一个布局xml文件,就像以前一样,我们需要在那个view中使用,就按照固定写法操作。在这个框架下我们的思维要稍稍改变一下了,以前的布局XML只描述了布局,它是相对固定的东西,在Data Binding Library下我们的布局XML就像是一个类,他可以有变量也能进行一定的运算。其实Data Binding Library还真的给你生成了一个类似这样的类(这个类在绑定数据时会用到,命名规则:activity_main.xml—》ActivityMainBinding)。
<?xml version="1.0" encoding="utf-8"?><layout xmlns:android="http://schemas.android.com/apk/res/android"><!--layout层,不是常见的5种布局;命名空间--> <data> <import type="com.xfyb.mvvmtest.User"></import><!--导包,一次导入,下面都可以使用该类。前提是我们已经创建出来了该类--> <variable name="user" type="User"/><!--创建对象--> </data> <!--原有的文件--> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.name}"/><!--View中使用变量用@{} 格式来调用--> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="change" android:text="change"/> </LinearLayout></layout>第二步:定义数据对象 在上面中我们提到需要创建User的对象,因此我们需要将其创建出来。
public class User { PRivate String Name; public void setAge(int age) { this.age = age; } public void setName(String name) { Name = name; } private int age; public User(String name, int age) { Name = name; this.age = age; } public int getAge() { return age; } public String getName() { return Name; }}这个类就是一个简单的Bean类,也就是我们在View中需要调用的对象属性。
第三步:绑定数据
public class MainActivity extends AppCompatActivity { User user; ActivityMainBinding binding;//自动生成的类ActivityMainBinding其实就是代表了那个布局,里面包括了布局的View,我们声明的变量。 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); /* setContentView(R.layout.activity_main);*/ binding = DataBindingUtil.setContentView(this, R.layout .activity_main);//原来设置布局的setContentView改成了DataBindingUtil.setContentView user = new User("XK",18);//创建对象,赋初始值 binding.setUser(user); } public void change (View view){ user.setName("KX"); binding.setUser(user); }}基于以上三步,我们就将基于Data Binding 的MVVM的简单编写就完成了,当我们实际运行时,如下界面:
但是当我们点击BUTTON时发现无法更改name的值,无法刷新textView。 解决方案: 1、让实体类继承BaSEObservable类
修改后的代码如下所示:
public class User extends BaseObservable {//继承自BaseObservable private String Name; public void setAge(int age) { this.age = age; } public void setName(String name) { Name = name; } private int age; public User(String name, int age) { Name = name; this.age = age; } @Bindable//添加注解 public int getAge() { return age; } @Bindable public String getName() { return Name; }}当我们再次点击时,就会修改name属性的值。
至此我们对于MVVM的简单应用就完成了,对于此应用我们主要是注意书写的规范及格式就可以了,特别是对于xml的文件的配置、User类的注解和绑定数据使用时的规范。
总结: 使用基于Data Binding的操作有以下优势:
1、不需要在Activity里写很多的findViewById2、在xml中我们只需要通过import导入需要的类的全包名,下面都可以使用。3、引用绑定数据的对象时的格式:以@开始,以{}包裹的形式出现,而内容呢?是user.name。user就是我们上面定义的variable。1、使用类中方法
定义一个静态方法public static String capitalize(final String Word) { if (word.length() > 1) { return String.valueOf(word.charAt(0)).toUpperCase() + word.substring(1); } return word; }在 xml 的 data 节点中导入: <import type="com.xfyb.mvvmtest.MyStringUtils"></import>使用方法与 java 语法一样:<TextView android:text="@{MyStringUtils.capitalize(user.name)}" android:layout_width="wrap_content" android:layout_height="wrap_content"/>总结:
使用类中的方法,注意方法的参数和返回值,否则无法正常生成ActivityMainBinding类,导致编译失败使用类中的方法,与常见的java一样,可以是通过静态方法,也可以与简单应用中对于name的引用一样采用“variable”的格式。
2、类型别名 如果我们在 data 节点了导入了两个同名的类怎么办?
<import type="com.example.home.data.User" /><import type="com.examle.detail.data.User" /><variable name="user" type="User" />这样一来出现了两个 User 类,那 user 变量要用哪一个呢?不用担心,import 还有一个 alias 属性。
<import type="com.example.home.data.User" /><import type="com.examle.detail.data.User" alias="DetailUser" /><variable name="user" type="DetailUser" />3、Null Coalescing 运算符
android:text="@{user.displayName ?? user.lastName}"就等价于
android:text="@{user.displayName != null ? user.displayName : user.lastName}"4、属性值 通过 @{} 可以直接把 Java 中定义的属性值赋值给 xml 属性。
<TextView android:text="@{user.lastName}" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>5、Observable Binding 要实现 Observable Binding,首先得有一个 implement 了接口 android.databinding.Observable 的类,为了方便,Android 原生提供了已经封装好的一个类 - BaseObservable,并且实现了监听器的注册机制。我们可以直接继承 BaseObservable。
public class User extends BaseObservable { private String Name; public void setAge(int age) { this.age = age; notifyPropertyChanged(BR.age); } public void setName(String name) { Name = name; notifyPropertyChanged(BR.name);//通知改变属性 } private int age; public User(String name, int age) { Name = name; this.age = age; } @Bindable public int getAge() { return age; } @Bindable public String getName() { return Name; }}BR 是编译阶段生成的一个类,功能与 R.java 类似,用 @Bindable 标记过 getter 方法会在 BR 中生成一个 entry。 通过代码可以看出,当数据发生变化时还是需要手动发出通知。 通过调用 notifyPropertyChanged(BR.firstName) 可以通知系统 BR.firstName 这个 entry 的数据已经发生变化,需要更新 UI。
6、带 ID 的 View 在使用Data Binding 有效降低了代码的冗余性,甚至完全没有必要再去获取一个 View 实例。我们可以直接在xml中使用id就可以了
<TextView android:id="@+id/tv_show" android:layout_width="wrap_content" android:layout_height="wrap_content"/>在代码中我们可以直接通过banding中找到(类似于java中的类和属性)。
binding.tvShow.setText("xxxx");//直接同对象.属性 获取到运行后的效果:
新闻热点
疑难解答