观察者模式--DataBinding的原理和坑

本文深入探讨了DataBinding的实现原理,解析其如何基于观察者模式更新UI,同时指出了使用过程中可能遇到的问题及应对策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一次我们介绍了DataBinding的应用,不过只在应用层面描述了下,没有做深入分析。
关于DataBinding的实现原理,它的根本思想是观察者模式。
这篇会结合上次的demo来分析它的原理和坑,关于demo源码可以在后台回复”数据绑定”获得。

回顾观察者模式

关于观察者模式有一篇详细的文章可以看看,
重新认识观察者模式
简单的说,当数据发生变化的时候,通过 notify通知观察者去做update。
如果把DataBinding用观察者模式来分析的话,
以这一篇demo的例子来说,
Android UI开发利器-DataBinding
Demo中的UerInfo是数据,当它数据发生改变的时候,notify观察者去更新UI。

DataBinding的观察者

问题回到demo中来,我们并没有在demo里看到观察者相关的代码,像demo的MainActivity,并没有被通知时的回调,那么DataBinding是怎么做到的呢。

实际上DataBinding这样的设计是合理的。数据绑定框架的目标就是免除开发者繁琐的操作UI,它帮我们做这些事情就好了。
所以它通过注解在编译期生成了ActivityMainBinding类,就是下面这里

public class MainActivity extends Activity {
    ....
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        mUser = new UserInfo();
        binding.setUser(mUser);
    }

ActivityMainBinding可以理解为观察者,它的父类是ViewDataBinding,
它有个抽象方法

/**
 * @hide
 */
protected abstract void executeBindings();

所有的layout都会生成一个Binding类,这个类继承ViewDataBinding,然后实现了execute*方法。
理解DataBinding框架的关键代码就在这里,其他可以选择性忽略,我们看代码的时候是这样的,先抽脉络,细枝末节的处理可以在理解了框架之后再慢慢体会。
下面是这个抽象方法的具体实现逻辑,这些代码都是DataBinding帮我们生成的。

@Override
protected void executeBindings() {
    long dirtyFlags = 0;
    synchronized(this) {
        dirtyFlags = mDirtyFlags;
        mDirtyFlags = 0;
    }
    java.lang.String userName = null;
    java.lang.String stringValueOfUserAge = null;
    int userAge = 0;
    com.phoenix.databindingdemo.UserInfo user = mUser; //<--我们传入的对象

    if ((dirtyFlags & 0xfL) != 0) {
        if ((dirtyFlags & 0xbL) != 0) {
                if (user != null) {
                    // read user.name
                    userName = user.getName();//<--UserInfo类中注解标识的get方法
                }
        }
        if ((dirtyFlags & 0xdL) != 0) {
                if (user != null) {
                    // read user.age
                    userAge = user.getAge();//<--UserInfo类中注解标识的get方法
                }
                // read String.valueOf(user.age)
                stringValueOfUserAge = java.lang.String.valueOf(userAge);//<--layout中的String.valueOf
        }
    }
    // batch finished
    if ((dirtyFlags & 0xdL) != 0) {
        // api target 1
        android.databinding.adapters.TextViewBindingAdapter.setText(this.tvAge, stringValueOfUserAge); //<--设置UI的操作
    }
    if ((dirtyFlags & 0xbL) != 0) {
        // api target 1
        android.databinding.adapters.TextViewBindingAdapter.setText(this.tvName, userName); //<--设置UI的操作
    }
}

重点的部分都用”//<–”标注了出来,对比demo中的代码就可以理解。
我们在activity中把 mUser对象传入了binding类,在每次对它进行set操作的时候都会触发notify,
之后DataBinding框架会回调execute方法,
框架通过注解拿到get方法,然后拿到和UI所对应的数据,之后结合layout中对应的标注去更新UI。
整个观察者模式的逻辑基本就是这样。

DataBinding的坑

官网上的demo很简单,简单到UserInfo中的所有字段都是string,它并没有告诉我们当字段是int时会有什么问题。
如果你看了上面的execute方法的实现,多少应该能猜出来,假设我们没有在layout中对age写String.valueOf方法的话,
userAge就是一个int对象,它会在这里被直接setText

// batch finished
if ((dirtyFlags & 0xdL) != 0) {
    // api target 1
    android.databinding.adapters.TextViewBindingAdapter.setText(this.tvAge, userAge); //<--设置UI的操作
}

对setText传一个int值,会被当做Resource索引,然后导致崩溃。如果你是刚接触DataBinding的新手,估计会看到下面这种崩溃原因

Resource #0x0

原因就是缺少了String.valueOf调用了。

DataBinding的缺点

它的缺点也很明显,我们现的开发工具Android Studio并没有对layout进行java语法校验的功能,而DataBinding很多骚操作都是在layout里用java语法进行标注的。所以一旦发生崩溃,崩溃的log都在java层,开发者并不知道我特么是在layout里少写了什么东西导致的。
所以这玩意见仁见智,适当的使用能大幅提高开发效率,而不理解原理下的使用可能反而会焦头烂额。
这里写图片描述

<think>好的,我现在需要回答用户关于Android DataBinding中双向绑定机制实现原理的问题。首先,我得回忆一下DataBinding的基本概念,然后深入探讨双向绑定的部分。 首先,用户提到了DataBinding的双向绑定,所以需要明确什么是双向绑定。单向绑定是数据从模型流向视图,而双向绑定允许视图的变化也能自动更新模型中的数据。这在像EditText这样的输入控件中非常有用,用户输入后数据能自动更新到对应的数据模型。 接下来,我需要解释双向绑定的实现原理。可能涉及以下几个部分: 1. **数据观察机制**:DataBinding库使用观察者模式,当数据变化时通知视图更新,反之亦然。可能使用BaseObservableBindable注解,或者使用ObservableField等类。 2. **双向绑定的语法**:在布局文件中使用@={}符号,例如android:text="@={viewModel.userName}",这里的等号表示双向绑定。 3. **事件监听**:视图的变化如何触发数据更新。例如,EditText的TextWatcher监听文本变化,然后更新数据模型。 4. **底层实现**:可能涉及到生成的绑定类,这些类如何处理双向的数据流。比如,如何自动为控件添加监听器,并在数据变化时更新双方。 然后,需要确保回答结构清晰,分点说明。可能还需要引用一些官方文档或可靠资料来支持解释,但用户提供的引用似乎与KotlinJava生态相关,可能不太直接相关,但如果有合适的部分可以引用的话。 还需要注意用户提到的系统级指令,比如数学公式要用$...$,独立公式用$$...$$,但这个问题可能不太涉及数学公式,但如果有涉及的地方需要注意格式。此外,用中文回答,生成相关问题。 现在,需要组织这些思路成一个连贯的回答,分步骤说明双向绑定的机制,可能包括数据观察、绑定适配器、生成的代码等部分。同时,可能需要提到InverseBindingAdapter,因为这在双向绑定中用于处理反向的数据流,即从视图到模型。 还需要检查是否有遗漏的部分,例如数据变更时的通知机制,比如ObservableField的使用,或者LiveData在DataBinding中的整合,但用户的问题可能集中在双向绑定的基础原理上,所以可能不需要涉及LiveData,除非它相关。 最后,生成相关问题,例如如何自定义双向绑定,常见问题有哪些,或者与单向绑定的区别等。</think>### Android DataBinding双向绑定机制及实现原理 Android DataBinding的双向绑定允许**视图与数据模型之间的自动同步**:当数据变化时更新视图,当视图内容变化时自动回写数据。其核心实现分为以下几个步骤: --- #### 1. **数据观察机制** - **数据层**:使用`Observable`接口(如`BaseObservable`类)或`ObservableField`包装数据。 示例: ```kotlin class User : BaseObservable() { @Bindable var name: String = "" set(value) { field = value notifyPropertyChanged(BR.name) } } ``` 通过`@Bindable`注解`notifyPropertyChanged()`方法通知绑定类数据变化[^1]。 - **视图层**:DataBinding自动生成的绑定类(如`ActivityMainBinding`)监听数据变化,并更新对应视图。 --- #### 2. **双向绑定语法** 在布局文件中使用`@={}`符号建立双向绑定: ```xml <EditText android:text="@={viewModel.user.name}" /> ``` 这里的`@=`表示双向绑定,而`@`仅表示单向绑定。 --- #### 3. **反向绑定适配器(Inverse Binding Adapter)** 双向绑定的关键在于**处理视图到数据的反向更新**: - **正向绑定**:数据 → 视图,通过`@BindingAdapter`实现。 - **反向绑定**:视图 → 数据,通过`@InverseBindingAdapter`实现。 以`EditText`的文本绑定为例: ```java // 正向:将数据设置到视图 @BindingAdapter("android:text") fun setText(view: EditText, value: String?) { if (view.text.toString() != value) { view.setText(value) } } // 反向:从视图读取数据 @InverseBindingAdapter(attribute = "android:text") fun getText(view: EditText): String { return view.text.toString() } ``` --- #### 4. **事件监听与更新触发** DataBinding自动为视图添加事件监听器。例如,`EditText`会注册`TextWatcher`: ```java // 自动生成的代码片段 editText.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { inverseBindingListener.onChange(); // 触发反向更新 } }); ``` 当用户输入文本时,`inverseBindingListener`会调用反向绑定适配器,将新值写回数据模型。 --- #### 5. **底层实现流程** 1. **编译时**:APT生成绑定类,解析`@={}`并生成正向/反向绑定逻辑。 2. **运行时**: - 数据变化 → 通过`notifyPropertyChanged()`通知绑定类 → 更新视图。 - 视图变化 → 通过事件监听触发反向绑定 → 更新数据模型。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值