Android架构组件Jetpack databinding源码讲解

DataBinding简要##

准备###

保证Gradle插件版本不低于1.5.0-alpha1

修改对应模块的build.gradle:

dataBinding{
	enabled true
}

布局文件###

最外层根节点变为layout,新增节点data用来存放页面可能用的数据以及方法。

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
    </data>
    <!--原先的根节点(Root Element)-->
    <LinearLayout>
    ....
    </LinearLayout>
</layout>

数据对象###

需要注意的是在数据对象中必须实现每个属性的get和set方法。

public class User {
    private final String firstName;
    private final String lastName;

    public User(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }
}

如果需要双向绑定则需要继承BaseObservable类,该类实现了监听器的注册机制(未验证)。

public class ObservableUser extends BaseObservable {
    private String firstName;
    private String lastName;

    @Bindable
    public String getFirstName() {
        return firstName;
    }

    @Bindable
    public String getLastName() {
        return lastName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
        notifyPropertyChanged(BR.firstName);
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
        notifyPropertyChanged(BR.lastName);
    }
}

BR 是编译阶段生成的一个类,功能与 R.java 类似,用 @Bindable 标记过 getter 方法会在 BR 中生成一个 entry

通过代码可以看出,当数据发生变化时还是需要手动发出通知。 通过调用 notifyPropertyChanged(BR.firstName) 可以通知系统 BR.firstName 这个 entry 的数据已经发生变化,需要更新 UI。

Variable和import###

这两个标签是在layout资源文件中data标签的下级标签,其中variable标签可以独自使用,其独自使用方法如下:

<data>
	<variable name="user" type="com.xxx.xxx.xxx.User" />
</data>

其中name对应的字段会在具体view控件赋值时用到,type字段对应值是具体引用的类的全路径。

variable和import方法联合使用方法如下:

<data>
    <import type="com.xxx.xxx.xxx.User" />
    <variable name="user" type="User" />
</data>

import使用方法与java类似,当使用了import后,variable的type标签就可以使用类名而不是全路径了

多个路径类名相同的解决方法###

<import type="com.example.home.data.User" />
<import type="com.examle.detail.data.User" alias="DetailUser" />
<variable name="user" type="DetailUser" />

如上面代码所示当引用了不同路径的两个 User 类时,需要给其中一个设置别名alias,这样在给variable标签中的type字段赋值时就可以避免冲突。

绑定variable####

当设置了variable标签后,框架会自动生成一个继承自ViewDataBinding的类,如果data中有class属性,比如

<data class="com.example.CustomBinding">
</data>

则生成的类名为CustomBinding,否则就根据layout的文件名来生成对应的Binding类,例如R.layout.activity_main对应生成的类名为ActivityMainBinding。自动生成的类在build目录下,as中不可见。

具体在Activity中的绑定方法如下

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ActivityBasicBinding binding = DataBindingUtil.setContentView(
            this, R.layout.activity_basic);
    User user = new User("fei", "Liang");
    binding.setUser(user);
}

用DataBindingUtil.setContentView来获取一个ActivityBasicBinding的实例binding来实现绑定,binding通过set方法来设置variable中对应的属性。

除了setContentView方法外,DataBindingUtil还提供了一个静态方法bind(View v)来实现xml和对应的ViewDataBinding的绑定。该方法可以用于adper和fragment中的xml绑定。

使用variable####

数据与 Variable 绑定之后,xml 的 UI 元素就可以直接使用了。使用方法为:属性="@{[variable.name].[property]}"例如:

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

java类静态方法的使用###

首先定义一个静态方法

public class MyStringUtils {
    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.liangfeizc.databindingsamples.utils.MyStringUtils" />

使用方法与 Java 语法一样:

<TextView
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:text="@{MyStringUtils.capitalize(user.firstName)}" />

BindingAdapter###

public class TestUtils{
	@BindingAdapter("bind:imageUrl")
	public static void imageLoader(ImageView view,String url){
		ImageLoader.getInstance().display(url,view)
	}
}

<?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">
	<data >
		<import type="com.vip.vf.android.home.api.model.ActiveModel"></import>
		<import type="com.vip.vf.android.common.uitils.TestUtils"></import>
		<variable
            name="model"
            type="ActiveModel"/>
        <variable
            name="isBottom"
            type="boolean"/>
        <variable
            name="utils"
            type="TestUtils"/>
        <variable
            name="imageUrl"
            type="String"/>
    </data>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="@color/vfWhiteColor">
        <ImageView
            android:id="@+id/image"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitXY"
            app:imageUrl = "@{imageUrl}"
            />
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </RelativeLayout>
</layout>

以上代码实现的功能是通过设置xml中的imageUrl属性来调用java文件中TestUtils的方法imageLoader,具体需要加载图片的时候只要调用相应的binding class的setimageUrl方法即可完成,可以有效的避免在Activity代码中多次引用ImageLoader这个方法。

最后

文末放一个小福利给大家,扫描下方二维码:

群内有许多技术大牛,有任何问题,欢迎广大网友一起来交流,群内还不定期免费分享高阶Android学习视频资料和面试资料包~

偷偷说一句:群里高手如云,欢迎大家加群和大佬们一起交流讨论啊!

猜你喜欢

转载自blog.csdn.net/m0_56255097/article/details/130094568