Android DataBinding的简单使用

 官方文档地址:https://developer.android.google.cn/topic/libraries/data-binding       

        先说说开发环境,本人使用的Android Studio 版本为3.5,gradle版本是5.4.1,在此之下的版本不确保能用。

        要使用DataBinding需要在项目对应的gradle文件中添加以下的设置

android {
    ........
    //介绍网址https://developer.android.google.cn/jetpack/androidx/releases/databinding
    dataBinding {
        enabled = true
    }
}
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    implementation 'androidx.appcompat:appcompat:1.1.0'//包含大部分androidx的类
}

        创建数据实体类User.java和类型转换工具类Converter.java,看不懂这两个类没关系,后面会用到,看完后面再回头看这两个类的作用。(ViewModel的介绍可以看我另外一篇文章Android ViewModel的使用

import androidx.databinding.ObservableField;
import androidx.lifecycle.ViewModel;

public class User extends ViewModel {
    public String name;
    public int age;
    public final ObservableField<String> observableName = new ObservableField<>();//可观察的数据对象
    public final ObservableField<Integer> observableAge = new ObservableField<>();
    public User(){
        name = "name";
        age = 18;
        observableName.set("observableName");
        observableAge.set(8);
    }
}
import android.util.Log;
import androidx.databinding.InverseMethod;
/**
 * 数据类型装换工具类
 * 每种类型装换必须有两个方法相互对应
 * 有@InverseMethod注解的是在布局文件中双向绑定时可以调用的方法
 * 没有@InverseMethod注解的方法看起来没有用到,但实际在双向绑定时会被自动调用
 */
public class Converter {
    @InverseMethod("stringToInt")//对应下面stringToInt方法
    public static String intToString(int value) {
        Log.d("JohnLiu","intToString:"+ value);
        return  String.valueOf(value);
    }

    public static int stringToInt(String value) {
        Log.d("JohnLiu","stringToInt:"+ value);
        if (Long.valueOf(value) > Integer.MAX_VALUE){
            throw new RuntimeException("数值超出");
        }
        return  Integer.valueOf(value);
    }
}

  Activity和layout文件如下(tips,如果遇到项目编译失败,检查一下Activity文件所在的文件目录是否符合规范,文件夹名称为小写。还有一种情况,通过File-》Invalidate Caches/Restart 清缓存并重启)。

import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;

public class DataBindingActivity extends AppCompatActivity {
    //系统会为每个布局文件生成一个绑定类。默认情况下,类名称基于布局文件的名称,它会转换为 Pascal 大小写形式并在末尾添加 Binding 后缀。
    // 本Activity布局文件名为 activity_data_binding,因此生成的对应类为 ActivityDataBindingBinding
    private ActivityDataBindingBinding mBinding;
    private User user;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        user = new User();//等价于user = ViewModelUtils.getPrivateViewModel(this,User.class,this);
//        user = ViewModelUtils.getViewModel(this,User.class);//全局唯一,即在app退出之前,下次重新进来这个页面会加载上一次的数据
        //DataBindingUtil输入的时候AS有可能不会智能提示,需要手动导入一下androidx.databinding.DataBindingUtil
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_data_binding);
        //根据绑定的layout中的variable标签里name设置的值变化,比如我设置的是data,这里方法就是setData,如果设置成user,这里就是setUser,如此类推
        mBinding.setData(user);
        findViewById(R.id.bt_set).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //值变化,但屏幕没刷新,需要手动调用一次 mBinding.setData(user);
                user.name="JohnLiu";
                user.age =  20;
                //只要值变化,数据就会同步显示到屏幕上
                user.observableName.set("JohnLiu");
                user.observableAge.set(20);
            }
        });
        findViewById(R.id.bt_refresh).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //调用一次 mBinding.setData(user);后可以看到前两行的值也刷新了
                mBinding.setData(user);
            }
        });

        findViewById(R.id.bt_toast).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String msg = "name:" + user.name + "\n"
                        + "age:" + user.age + "\n"
                        + "observableName:" + user.observableName.get() + "\n"
                        + "observableAge:" + user.observableAge.get();
                //显示当前实体类中所有变量的值
                Toast.makeText(DataBindingActivity.this,msg,Toast.LENGTH_SHORT).show();
            }
        });

    }
}

其中activity_data_binding.xml的内容如下

<?xml version="1.0" encoding="utf-8"?>
<layout
    xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <import type="com.jetpackdemo.databinding.Converter"/>
        <!--假如要导入两个同名的类,可以通过alias设置别名-->
        <!-- <import type="com.jetpackdemo.Converter" alias="Converter2"/>-->
        
        <!--data实体类,type字段的值是User类的具体路径-->
        <variable
            name="data"
            type="com.jetpackdemo.databinding.User" />
    </data>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/layout"
        android:orientation="vertical">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="赋值"
                android:id="@+id/bt_set"/>
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="刷新"
                android:id="@+id/bt_refresh"/>
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="当前值"

                android:id="@+id/bt_toast"/>
        </LinearLayout>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{data.name}"
            />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(data.age)}"
            />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="单向绑定,修改实体类的值,实时刷新屏幕显示的值"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{data.observableName}"
            />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(data.observableAge)}"
            />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="双向绑定,在输入框修改值也会自动更新实体类的值"/>
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@={data.observableName}"
            />
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:inputType="number"
            android:text="@={Converter.intToString(data.observableAge)}"
            />
    </LinearLayout>

</layout>

刚启动的页面如下:

点击赋值&当前值,可以看到虽然实体类中的值变了,但是前两行文本没有同步刷新

                

点击刷新,可以看到前两行文本也刷新了,这就是用了可观察对象ObservableField与没用的区别。ObservableField会监听值的变化,实时刷新屏幕。

修改最后两行的文本,可以看到修改视图中的文本,同时会修改实体类中相应的可观察对象的值,实现数据双向绑定。是否实现双向绑定,区别在于 android:text="@={Converter.intToString(data.observableAge)}" 里面的“@”后面有无“=”,如果没有“=”,修改实体类中的值,会刷新视图,但修改视图,不会同时修改实体类的值。

 

小结

        从效果看来,使用DataBinding好像减少很多代码,大部分的取/赋值操作自动完成 ,不需要关注值的变化去更新视图。但实际业务大多数要对数据的格式或取值进行校验并做一些处理,并不仅仅只是把值赋给实体对象。还有,可以看到DataBinding的赋值逻辑是写在XML的布局文件上的,但实际上有时候我们需要动态地往布局添加一些组件,这个时候又怎么处理呢?或许只是我对它的了解还不够深吧,但目前它给我的感觉是比较难运用到实际业务当中去。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Data Binding 是一种 Android 平台提供的技术,它可以将 View 上的属性与数据模型中的数据绑定在一起,使得数据变化时,View 上的属性也能够自动更新。下面是一个简单的例子,演示如何使用 Data Binding。 1. 首先,需要在 app 的 build.gradle 文件中添加以下依赖: ``` android { ... dataBinding { enabled = true } } dependencies { ... implementation 'com.android.databinding:compiler:3.1.4' } ``` 2. 创建一个布局文件,例如 activity_main.xml: ```xml <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="user" type="com.example.User" /> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:text="@{user.name}" android:layout_width="match_parent" android:layout_height="wrap_content" /> <TextView android:text="@{String.valueOf(user.age)}" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> </layout> ``` 这个布局文件中定义了一个名为 `user` 的变量,类型为 `com.example.User`,并且在两个 TextView 中使用了 `@{}` 语法,表示需要将 `user` 对象中的 `name` 和 `age` 属性分别绑定到这两个 TextView 上。 3. 创建一个 Java 类,例如 User.java: ```java public class User { public String name; public int age; } ``` 这个类中定义了两个属性 `name` 和 `age`。 4. 在 Activity使用 Data Binding,例如 MainActivity.java: ```java public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); User user = new User(); user.name = "张三"; user.age = 18; binding.setUser(user); } } ``` 在 Activity 中,首先通过 `DataBindingUtil.setContentView()` 方法将布局文件绑定到 Activity 上,然后创建一个 `User` 对象并将其赋值给布局文件中定义的 `user` 变量。 5. 运行程序,可以看到界面上显示了 `张三` 和 `18`。 这个例子演示了如何使用 Data Binding 将数据模型中的数据与 View 上的属性进行绑定,当数据变化时,View 上的属性也能够自动更新。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值