美文网首页
DataBinding基础篇

DataBinding基础篇

作者: 麻油里 | 来源:发表于2019-03-27 09:41 被阅读0次

    DataBinding可以做些什么

    • 在xml中操作数据和事件
    • 自动绑定id,省去findViewById
    • 实现View和数据双向绑定

    引入

    在app或者lib的build.gradle中添加

    android {
        dataBinding {
            enabled = true
        }
    }
    

    2020.5.12更新
    在kotlin中使用时,为了支持注解处理,还需要另外添加

    apply plugin: 'kotlin-kapt'
    

    简单使用

    在原本的布局文件底层添加<layout>标签,实现对xml文件的DataBinding化。

    <?xml version="1.0" encoding="utf-8"?>
    <layout>
    
        <LinearLayout
            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"
            tools:context=".MainActivity"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center_horizontal"
            android:orientation="vertical">
    
           <TextView
               android:id="@+id/tv_name"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content" />
    
        </LinearLayout>
    </layout>
    

    这时,在Activity中,就可以对DataBinding进行初始化了。ActivityMainBinding是根据xml自动生成的一个类。名称是由xml文件名驼峰化+Binding后缀而来。如activity_main--->ActivityMainBinding。

    如果未找到类,rebuild就可以了。

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
            binding.tvName.setText("hello world");
        }
    
    }
    
    

    在给TextView设置id后,DataBinding会自动进行绑定,binding.tvName对应id为tv_name的TextView,同样是对命名进行了驼峰化。这样就省去了findViewById。相对于ButterKinfe,也省去了BindView的代码。

    至此,是DataBinding最最简单的使用,即省去findViewById。

    在xml中绑定数据

    为了方便理解,这里定义了一个UserBean类(注意,set方法必须要有),会在下面使用。

    public class UserBean {
    
        private String name;
    
        public UserBean(String name) {
            this.name = name;
        }
        
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    

    在xml中添加<data>标签

    <data>标签下添加<variable>标签

    <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"
        tools:context=".MainActivity">
    
        <data>
            <variable
                name="userBean"
                type="com.qianfanyun.lib.recyclerview.UserBean" />
        </data>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center_horizontal"
            android:orientation="vertical">
    
            <TextView
                android:id="@+id/tv_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                
                android:text="@{userBean.name}"
                
                />
    
        </LinearLayout>
    </layout>
    

    <data>固定在<layout>的下一层,在<data>内可以定义各种变量<variable>。

    <variable>有两个属性

    • name 变量名,可以随意取,在这个布局中不重复就可以了。
    • type 这个变量的类型,对应于某个类。

    <TextView>中text属性的值为@{userBean.name} userBean是上面定义的变量,我们要引用这个变量中的值,只需要用@{}包裹,并且调用 [上面定义的变量名.属性名]。最终DataBinding会调用到这个对象的对应属性的get方法。

    在java代码中,可以把这个对象设置进去。

      @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
            binding.setUserBean(new UserBean("ArcherYc"));
        }
    

    最终在这个页面中会显示ArcherYc这个文字。

    通过变量id设置值:

    binding.setVariable(BR.userBean,new UserBean("ArcherYc"));
    
    稍微总结下DataBinding的基本结构
    <layout>
    
        <data>
        </data>
        
        <root view>
        </root view>
        
    </layout>
    
    

    支持的表达式

    @{}内可以使用一下表达式

    • Mathematical + - / * %
    • String concatenation +
    • Logical && ||
    • Binary & | ^
    • Unary + - ! ~
    • Shift >> >>> <<
    • Comparison == > < >= <= (Note that < needs to be escaped as <)
    • instanceof
    • Grouping ()
    • Literals - character, String, numeric, null
    • Cast
    • Method calls
    • Field access
    • Array access []
    • Ternary operator ?:

    列如:

    表达式中存在双引号时,最外层用单引号。
    android:text='@{"name:"+user.name}'
    

    2020.5.15新增
    Null 合并运算符
    如果左边运算数不是 null,则 Null 合并运算符 (??) 选择左边运算数,如果左边运算数为 ,则选择右边运算数。

    android:text="@{user.displayName ?? user.lastName}"
    

    这在功能上等效于:

    android:text="@{user.displayName != null ? user.displayName : user.lastName}"
    

    空安全

    DataBinding在variable对象为空时,会在用到variable的地方填充默认值,所以不需要担心报空指针异常。

    使用资源

    在实际项目中,可能会出现一个布局的参数需要根据类型,动态改变,这时使用下面这种方法可以方便的改变。这样就避免了使用LayoutParams来修改。

    android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"
    

    事件传递

    两种方案设置处理事件

    • 方法引用 类似于OnClick调用Activity中的方法。
    • 监听绑定

    方法引用

    定义一个方法,用于处理点击事件。有且仅有一个参数View。方法必须为public。
    在绑定事件时调用

    public class Handler{
        public void onClick(View view){
            Toast.makeText(MainActivity.this, "onClick", Toast.LENGTH_SHORT).show();
        }
    }
    

    在data中申明方法所在类的对象

    <data>
        <variable
            name="handler"
            type="com.qianfanyun.databinding.MainActivity.Handler"/>
    </data>
    

    设置onClick

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="@{handler::onClick}"
        />
    

    在DataBinding中设置对象

    binding.setHandler(new Handler());
    

    方法引用是在把处理对象设置进去的时候,设置了监听。即setHandler。

    监听绑定

    申明一个处理事件的方法。不需要特定参数,可以自定义参数。方法必须为public。
    在事件发生时调用

    public class Handler{
        public void onClick(String name){
            Toast.makeText(MainActivity.this, name, Toast.LENGTH_SHORT).show();
        }
    }
    

    在data中申明方法所在类的对象

    <data>
        <variable
            name="handler"
            type="com.qianfanyun.databinding.MainActivity.Handler"/>
    </data>
    

    设置onClick ()->为固定格式 后面的表达式与java中使用语法相同

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick='@{()->handler.onClick("ArcherYc")}'
        />
    

    在DataBinding中设置对象

    binding.setHandler(new Handler());
    

    通过这种方式设置监听,是在事件发生时调用的。

    处理的方法可以添加自定义参数。

    支持传递调用处的对象,比如:

    android:onClick="@{(theView) -> presenter.onSaveClick(theView, task)}"
    
    public class Presenter {
        public void onSaveClick(View view, Task task){}
    }
    

    使用void来表示不处理

    android:onClick="@{(v) -> v.isVisible() ? doSomething() : void}"
    

    导入类

    在<data>内可以导入类在表达式中使用

    这里以导入View类为例

    <data>
        <import type="android.view.View"/>
        <variable
            name="user"
            type="com.qianfanyun.lib.recyclerview.UserBean"/>
    </data>
    
    <TextView
        android:id="@+id/tv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="ArcherYc"
        android:visibility="@{user.student?View.VISIBLE:View.GONE}"
        />
    

    导入的类可以调用其静态公共方法

    <import type="com.qianfanyun.databinding.StringUtils"/>
    
    <TextView
        android:id="@+id/tv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="ArcherYc"
        android:visibility="@{!StringUtils.isEmpty(user.name)?View.VISIBLE:View.GONE}"
        />
    

    当名称产生冲突时,可以增加alias属性来解决冲突

    <import type="com.qianfanyun.databinding.View"
        alias="myView"/>
        
    <import type="android.view.View"/>
    

    java.lang.*是自动导入的

    include

    DataBinding支持include。include中要使用变量,需要进行传递。

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_horizontal"
        android:orientation="vertical">
        <include
            android:id="@+id/include"
            layout="@layout/name"
            bind:user="@{user}" />
    </LinearLayout>
    

    在include的布局中使用变量

    <layout>
        <data>
            <variable
                name="user"
                type="com.qianfanyun.lib.recyclerview.UserBean"/>
        </data>
        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:orientation="vertical" android:layout_width="wrap_content"
            android:layout_height="wrap_content">
            <TextView
                android:id="@+id/tv_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{user.name}"
                />
        </LinearLayout>
    </layout>
    

    获取include中的变量对象。必须要先给<include>标签设置id。

    binding.include.tvName.setText("ArcherYc");
    

    参考

    相关文章

      网友评论

          本文标题:DataBinding基础篇

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