IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 记录每天学习的新知识:DataBinding -> 正文阅读

[移动开发]记录每天学习的新知识:DataBinding

前言

Jetpack 是一个丰富的组件库,它的组件库按类别分为 4 类,分别是架构(Architecture)、界面(UI)、 行为(behavior)和基础(foundation)。

每个组件都可以单独使用,也可以配合在一起使-用。每个组件都给用户提供了一个标准, 能够帮助开发者遵循最佳做法,减少样板代码并编写可在各种 Android 版本和设备中一致运行的代码,让开发者能够集中精力编写重要的业务代码。

在这里插入图片描述

DataBinding 是 Google 在 Jetpack 中推出的一款数据绑定的支持库,利用该库可以实现在页面组件中直接绑定应用程序的数据源。使其维护起来更加方便,架构更明确简介。

使用前需要了解

运行环境:
Android Studio Chipmunk | 2021.2.1 Patch 1
Build #AI-212.5712.43.2112.8609683, built on May 19, 2022
Runtime version: 11.0.12+7-b1504.28-7817840 amd64

  • 应用DataBinding,在App的build.gradle:
android {
    buildFeatures {
//        viewBinding = true
        dataBinding = true
    }
  • 想在哪个页面使用DataBinding,就修改对应的布局文件
    添加 layout 标签
<?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">

    
    <!--我的布局文件-->
    <androidx.constraintlayout.widget.ConstraintLayout

        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

	// .... 布局内容

    </androidx.constraintlayout.widget.ConstraintLayout>

</layout>
  • 编译后就会有对应布局的binding了
    ActivityMainBinding mBinding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(R.layout.activity_main);

//        mBinding = ActivityMainBinding.inflate(getLayoutInflater());
//        setContentView(mBinding.getRoot());

       mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

注意:DataBinding实现了ViewBinding ,所以ViewBinding的用法也适用。

一、基础用法

当前事例实现:

  • 向XML中设置指定的Data格式数据,提供给View引用
  • 向XML设置点击事件
  • 向XML设置方法所在类,调用静态方法
  • 引用string资源文件

XML

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <!--提供方法的类-->
        <import type="com.yoshin.kt.demo_databinding.StringUtils" />
        <!--点击事件-->
        <import type="com.yoshin.kt.demo_databinding.MainActivity.Listener" />
        <!--实体类-->
        <variable
            name="student"
            type="com.yoshin.kt.demo_databinding.bean.Student" />
        <!--实体类-->
        <variable
            name="student2"
            type="com.yoshin.kt.demo_databinding.bean.Student" />
        <!--点击事件-->
        <variable
            name="lintener"
            type="Listener" />
    </data>

    <!--我的布局文件-->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:gravity="center"
            android:text="你好 世界!" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:gravity="center"
            android:onClick="@{()->lintener.onClick(student)}"
            android:text="@{@string/student_name + student.name,default = 小明}"
            android:textColor="@color/teal_200" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:gravity="center"
            android:text="@{StringUtils.getAge(student.year)}"
            android:textColor="@color/teal_200" />

        <EditText
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:afterTextChanged="@{lintener.afterStudentNameChanged}"
            android:gravity="center"
            android:text="@{@string/student_2 + @string/student_name + student2.name,default = 小明}"
            android:textColor="@color/teal_200" />

    </LinearLayout>

</layout>

Activity

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ActivityMainBinding mBinding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(mBinding.getRoot());

        Student student = new Student();
        student.setName("小黑");
        student.setYear("18");

        Student student2 = new Student();
        student2.setName("小绿");

        mBinding.setStudent(student);
        mBinding.setStudent2(student2);

        mBinding.setLintener(new Listener());

    }


    public class Listener {

        public void onClick(Student student) {
            Toast.makeText(MainActivity.this, student.getName(), Toast.LENGTH_SHORT).show();
        }

        public void afterStudentNameChanged(Editable editable) {
            Toast.makeText(MainActivity.this, editable.toString(), Toast.LENGTH_SHORT).show();
        }
    }

此时的写法,数据没有绑定

在这里插入图片描述

二、引入布局(include、viewStub)

以 include 为例(DataBinding不支持merge标签):

view_include_patriarch.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
            name="patriarch"
            type="com.yoshin.kt.demo_databinding.bean.Patriarch" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:gravity="center"
            android:text="@{@string/str_name + patriarch.name,default = 小明的爸爸}"
            android:textColor="@color/teal_200" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</layout>

main.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:binding="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <!--提供方法的类-->
        <import type="com.yoshin.kt.demo_databinding.StringUtils" />
        <!--点击事件-->
        <import type="com.yoshin.kt.demo_databinding.MainActivity.Listener" />

        <!--实体类-->
        <variable
            name="student"
            type="com.yoshin.kt.demo_databinding.bean.Student" />
        <!--实体类-->
        <variable
            name="student2"
            type="com.yoshin.kt.demo_databinding.bean.Student" />

        <!--点击事件-->
        <variable
            name="lintener"
            type="Listener" />

    </data>

    <!--我的布局文件-->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">

		...<include
            android:id="@+id/ic_patriarch"
            layout="@layout/view_include_patriarch"
            binding:patriarch="@{student.patriarch}" />

    </LinearLayout>

</layout>

需要在main.xml里添加:

    xmlns:binding="http://schemas.android.com/apk/res-auto"

但是鼓捣了半天都引用不到属性

在这里插入图片描述
不过没有关系!!!硬写吧,是好用的~ 这应该是个BUG吧

参考:dataBinding中使用include :https://blog.csdn.net/chuyouyinghe/article/details/124354463

三、单向绑定 (Data变化通知View)

如下事例延续上面的操作续写

1、BaseObservable

public class Student extends BaseObservable {

    @Bindable
    private String name;

    @Bindable
    private String year;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getYear() {
        return year;
    }

    public void setYear(String year) {
        this.year = year;
        notifyPropertyChanged(BR.year);
    }

}

如上,如果通过 setYear(String year) 方法设置 year时,如果数据有变化就会通知View进行更新,通过重写 TextView.setText()方法确认了这一点,如果数据无变换不会通知到View更新;
setName(String name) 调用不会通知View更新,因为没有调用到 notifyPropertyChanged(id)

  • @Bindable
    需要使用到更新的Key,需要添加此注解

  • notifyPropertyChanged(int fieldId)
    如果个Key,数据改变,就更新View

  • notifyChange()
    刷新所有Key

2、ObservableField

参考 :Android 安卓DataBinding(四)·单向绑定 ObservableField:https://blog.csdn.net/qq_40881680/article/details/101847386

续写测试ObservableField

参考上面做的,我这里也不好使啊,记一下!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!不好使!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

public class Student extends BaseObservable {

    private final ObservableField<String>  name = new ObservableField<>();

    private final ObservableField<String> year = new ObservableField<>();

    private final ObservableField<Patriarch> patriarch = new ObservableField<>();


    public String getName() {
        return name.get();
    }

    public void setName(String name) {
        this.name.set(name);
    }

    public String getYear() {
        return year.get();
    }

    public void setYear(String year) {
        this.year.set(year);
    }

    public Patriarch getPatriarch() {
        return patriarch.get();
    }

    public void setPatriarch(Patriarch patriarch) {
        this.patriarch.set(patriarch);
    }

}

在调用如下代码时,XML没有跟着实时刷新啊,(⊙o⊙)…不理解源码的痛

student.setYear(String.valueOf(System.currentTimeMillis()));
public class Patriarch {

    /**
     * 继承 BaseObservableField 父类继承 BaseObservable 实现 Observable
     */
    private ObservableField<String> name;
    private ObservableInt intId;
    private ObservableLong longId;
    private ObservableDouble doubleId;
    private ObservableBoolean isOk;
    private ObservableByte oByte;
    private ObservableFloat floatId;
    private ObservableChar charId;
    private ObservableShort shortId;

    public Patriarch() {
        name = new ObservableField<>();
    }

    /**
     * 继承 ObservableField
     */
    private ObservableParcelable<Friend> friend;

    public String getName() {
        return name.get();
    }

    public void setName(String name) {
        this.name.set(name);
    }

    /**
     * 继承 List
     */
    ObservableList<String> list;
    ObservableArrayList<String> arrayList;

    /**
     * 继承 Map
     */
    ObservableMap<String, String> map;
    ObservableArrayMap<String, String> arrayMap;

}

先这样吧 。没好使。

四、双向绑定 (Data变化通知View,View变化反馈给数据)

        <TextView
            android:id="@+id/tv_2"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:gravity="center"
            android:onClick="@{()->lintener.onClick(student)}"
            android:text="@={student.name,default = 小明}"
            android:textColor="@color/teal_200" />

如上,即双向绑定的写法

@={student.name,default = 小明}

区别于正常写法,需要多写个=

注意是,如果写了“=”就不能直接引用string文件了,也不能引用静态方法。

测试的时候,配合的是 标题三、单向绑定,中的 1.BaseObservable进行的测试,验证双向绑定OK

五、配合LiveData的写法

1、事例延续上面代码修改,做双向绑定

  • ViewModel
public class MainViewModel extends AndroidViewModel {

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

    final MutableLiveData<Student> mutableLiveData = new MutableLiveData<>();

    public MutableLiveData<Student> getMutableLiveData() {
        return mutableLiveData;
    }

    public void setMutableLiveData(Student student) {
        mutableLiveData.setValue(student);
    }


    final MutableLiveData<String> stringMutableLiveData = new MutableLiveData<>();

    public MutableLiveData<String> getStringMutableLiveData() {
        return stringMutableLiveData;
    }

    public void setStringMutableLiveData(String str) {
        stringMutableLiveData.setValue(str);
    }

  • XML

    <data>

		....<variable
            name="viewModel"
            type="com.yoshin.kt.demo_databinding.MainViewModel" />

    <!--我的布局文件-->
    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            tools:context=".MainActivity">
			
			...<EditText
                android:id="@+id/tv_1"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:gravity="center"
                android:onClick="@{()->lintener.onClick(student)}"
                android:text="@={viewModel.mutableLiveData.name}"
                android:textColor="@color/teal_200" />


            <com.yoshin.kt.demo_databinding.MyTextView
                android:id="@+id/tv_2"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:gravity="center"
                android:text="@={viewModel.stringMutableLiveData}"
                android:textColor="@color/teal_200" />

  • 调用
public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    ActivityMainBinding mBinding;

    private MainViewModel mVM
            = ViewModelProvider.AndroidViewModelFactory.getInstance(this.getApplication()).create(MainViewModel.class);


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

		... 略

	    mBinding.setLifecycleOwner(this);
        mBinding.setViewModel(mVM);

        mVM.getMutableLiveData().observe(this, new Observer<Student>() {
            @Override
            public void onChanged(Student student) {
                Log.i(TAG, " getMutableLiveData observe  == " + new Gson().toJson(student));
            }
        });

        mVM.setMutableLiveData(student);

        mVM.getStringMutableLiveData().observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                Log.i(TAG, " getStringMutableLiveData observe  == " + new Gson().toJson(s));
            }
        });

        mVM.setStringMutableLiveData("这就是个String");

如此,可以实现双向绑定。

虽然实现了双向绑定,但是还有需要说的地方:
LiveData <T 的泛型 TJavaBean 还是String 类型,影响观察者模式的回调

  1. TStudent (JavaBean)

调用 mVM.setMutableLiveData(student); ,日志 getMutableLiveData observe == xxx 只会输出一次,无论值本身地址变化,还是内部数据变化;
调用 mBinding.tv1.setText(“xxxx”); ,日志 getMutableLiveData observe == xxx 不会输出,但是值本身是变化的(通过点击按钮打印,mutableLiveData 内部值是变化的)。

  1. TString

进入页面第一次调用 mVM.setStringMutableLiveData(str); ,日志 getStringMutableLiveData observe == xxx 会输出一次;
之后,调用 mVM.setStringMutableLiveData(str); ,如果值是有变化的,日志 getStringMutableLiveData observe == xxx 会输出两次,重写了TextView,发现setText()的方法,夹在中间;
如下:

 14:10:29.827 14131-14131/com.yoshin.kt.demo_databinding I/MainActivity:  getStringMutableLiveData observe  == "setString 修改后String的值"
 14:10:29.829 14131-14131/com.yoshin.kt.demo_databinding I/Main-MyTextView: setText
 14:10:29.832 14131-14131/com.yoshin.kt.demo_databinding I/MainActivity:  getStringMutableLiveData observe  == "setString 修改后String的值"

如果值没有变化,日志 getStringMutableLiveData observe == xxx 会输出一次;

调用 mBinding.tv2.setText(“xxxx”); ,日志 getStringMutableLiveData observe == xxx 会输出一次。

综上所述,推荐使用当 T(JavaBean) 的方式,容易控制。

2、引入布局场景

二、引入布局(include、viewStub)的写法在这就失效了,这里就要修改了,如下即可:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable
            name="viewModel"
            type="com.yoshin.kt.demo_databinding.MainViewModel" />
        <variable
            name="patriarch"
            type="com.yoshin.kt.demo_databinding.bean.Patriarch" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:gravity="center"
            android:text="@{@string/str_name + viewModel.mutableLiveData.patriarch.name,default = 小明的爸爸}"
            android:textColor="@color/teal_200" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</layout>

改成 传入 viewModel,就可以在数据改变的时候View更新。

六、BindingAdapter

用途: 支持自定义属性,或者是修改原有属性

  • 自定义属性

一个参数的

public class ImageBindingAdapter {

    @BindingAdapter("imageUrl")
    public static void setImageUrl(ImageView view, String url) {
        Log.i(TAG, "setImageUrl: ");
        Glide.with(view).load(url).into(view);
    }
            <ImageView
                imageUrl="@{viewModel.mutableLiveData.url}"
                android:layout_width="100dp"
                android:layout_height="100dp"/>

多个参数的

@BindingAdapter(value = {"imageUrl", "placeholder", "error"},requireAll = false)
public static void loadImage(ImageView view, String url, Drawable placeholder, Drawable error) {
    RequestOptions options = new RequestOptions();
    options.placeholder(placeholder);
    options.error(error);
    Glide.with(view).load(url).apply(options).into(view);
}
 <ImageView
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:layout_marginTop="10dp"
    app:imageUrl="@{`https://goss.veer.com/creative/vcg/veer/800water/veer-136599950.jpg`}"
    app:placeholder="@{@drawable/icon}"/>

  • 修改属性
public class TextViewAdapter {
    @BindingAdapter("android:text")
    public static void setText(TextView view, CharSequence text) {
        //省略特殊处理...
        String txt = text.toString().toLowerCase();
        view.setText(txt);
    }
}
        <!--使用dataBinding的TextView-->
        <TextView
            android:id="@+id/tvData"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:background="#a37c7c"
            android:text="@{`这是TextView...`}"
            android:textSize="16sp" />

这么写完,databinding都会调用这个方法,不推荐

转 Android Jetpack组件之BindingAdapter详解:https://blog.csdn.net/jzman/article/details/106699816

七、BindingConversion

Android Jetpack组件之BindingAdapter详解:https://blog.csdn.net/jzman/article/details/106699816

Android DataBinding 从入门到进阶,看这一篇就够:https://blog.csdn.net/Eqiqi/article/details/121670801

八、支持的运算符和关键字

绑定表达式支持的运算符和关键字

算术运算符 + - / * %
字符串连接运算符 +
逻辑运算符 && ||
二元运算符 & | ^
一元运算符 + - ! ~
移位运算符 >> >>> <<
比较运算符 == > < >= <=(请注意,< 需要转义为 <)
instanceof
分组运算符 ()
字面量运算符 - 字符、字符串、数字、null
类型转换
方法调用
字段访问
数组访问 []
三元运算符 ?:
Null 合并运算符 ??
属性引用.
集合操作[],可用于数组,列表,映射;
字面常量
资源@,但是有些资源类型需要显式指明;

Android-DataBinding-使用-高阶:https://www.jianshu.com/p/b5762e72f56f

参考地址

Android DataBinding 从入门到进阶,看这一篇就够:https://blog.csdn.net/Eqiqi/article/details/121670801

https://wenku.baidu.com/view/0a12a6356f175f0e7cd184254b35eefdc8d31592.html

https://developer.android.google.cn/jetpack/androidx/releases/databinding

转自 Android Jetpack架构全家桶,学完可从零搭建一个Android项目架构:http://px.sxjnk.cn/enjoy/advertorial/article_6

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-08-19 19:17:25  更:2022-08-19 19:18:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 5:01:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码