前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >观察者模式--DataBinding的原理和坑

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

作者头像
PhoenixZheng
发布2018-09-29 11:37:05
1.9K0
发布2018-09-29 11:37:05
举报

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

回顾观察者模式

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

DataBinding的观察者

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

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

代码语言:javascript
复制
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, 它有个抽象方法

代码语言:javascript
复制
/**
 * @hide
 */
protected abstract void executeBindings();

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

代码语言:javascript
复制
@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

代码语言:javascript
复制
// 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里少写了什么东西导致的。 所以这玩意见仁见智,适当的使用能大幅提高开发效率,而不理解原理下的使用可能反而会焦头烂额。

==== 今日沙雕 ====

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-08-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Android每日一讲 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 回顾观察者模式
  • DataBinding的观察者
  • DataBinding的坑
  • DataBinding的缺点
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档