文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Android-Jetpack笔记-DataBinding

2022-06-06 14:14

关注

DataBinding即数据绑定,可以实现数据和UI的

双向绑定
。数据改变时,驱动UI刷新;操作UI时,也可以同步给数据。通常在开发界面时,总有
findViewById
的重复工作,DataBinding可以免去这些操作。同时,DataBinding还可以直接在xml中绑定数据,免去类似
setText
的操作,让数据来驱动UI刷新。

Jetpack笔记代码

使用

app/build.gradle
中开启:

android {
    dataBinding {
        enabled = true
    }
}

在布局文件中,将光标定位在根布局,

alt+enter
,然后
convert to data binding layout

布局外层会多出一层layout标签:


    
    

在数据描述内,可以导入类和声明变量:


在布局描述内,定义一个TextView并绑定数据:


在activity中,通过

DataBindingUtil
得到binding对象:

void onCreate(Bundle savedInstanceState) {
    mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
}

其中xml文件名决定了生成的binding的类名,xml文件名+Binding,如

activity_main.xml
生成
ActivityMainBinding.java
,然后就可以通过binding对象直接访问到view:

mBinding.tvName.setTextColor(xxx);

通过binding对象设置数据,驱动UI刷新:

mBinding.setUser(user);
原理

DataBindingUtil.setContentView
作为入口跟进去,

//DataBindingUtil.java
public static  T setContentView(Activity activity,int layoutId,DataBindingComponent bindingComponent) {
    //这里设置了布局文件
    activity.setContentView(layoutId);
    return bindToAddedViews(bindingComponent, contentView, 0, layoutId);
}
//省略调用链:bindToAddedViews -> bind
static  T bind(DataBindingComponent bindingComponent, View root,int layoutId) {
    return (T) sMapper.getDataBinder(bindingComponent, root, layoutId);
}

来到

MergedDataBinderMapper.java

//MergedDataBinderMapper.java
@Override
public ViewDataBinding getDataBinder(DataBindingComponent bindingComponent, View view,int layoutId) {
    for(DataBinderMapper mapper : mMappers) {
        ViewDataBinding result = mapper.getDataBinder(bindingComponent, view, layoutId);
        if (result != null) {
            return result;
        }
    }
    return null;
}

那么

mMappers
的值是在什么时候设置的呢?发现只有一处进行add,

//MergedDataBinderMapper.java
public void addMapper(DataBinderMapper mapper) {
    Class mapperClass = mapper.getClass();
    //如果不在mExistingMappers中,才添加进mMappers
    if (mExistingMappers.add(mapperClass)) {
        mMappers.add(mapper);
        final List dependencies = mapper.collectDependencies();
        for(DataBinderMapper dependency : dependencies) {
            addMapper(dependency);
        }
    }
}

再来看看谁调了

addMapper
,发现有一个生成类
DataBinderMapperImpl
(data binding通过apt创建了一些类),

//DataBinderMapperImpl.java
package androidx.databinding;//注意包名
public class DataBinderMapperImpl extends MergedDataBinderMapper {
    DataBinderMapperImpl() {
        //构造的时候把另一个包下的生成类DataBinderMapperImpl添加进去
        addMapper(new com.holiday.jetpackstudy.DataBinderMapperImpl());
    }
}

接着看业务包名下的生成类

DataBinderMapperImpl

//DataBinderMapperImpl.java
package com.holiday.jetpackstudy;//注意包名
public class DataBinderMapperImpl extends DataBinderMapper {
  @Override
  public ViewDataBinding getDataBinder(DataBindingComponent component, View view, int layoutId) {
      int localizedLayoutId = INTERNAL_LAYOUT_ID_LOOKUP.get(layoutId);
      switch(localizedLayoutId) {
          case  LAYOUT_ACTIVITYMAIN: {
              if ("layout/activity_main_0".equals(tag)) {
                  //返回了binding的具体实现类
                  return new ActivityMainBindingImpl(component, view);
              }
          }
      }
  }
}

这里出现了tag,需要知道的是,DataBinding将布局文件拆成了两个文件,

activity_main.xml
描述布局,
activity_main-layout.xml
描述数据,
activity_main.xml
app/build/intermediates/incremental/mergeDebugResources/stripped.dir/layout/
这个目录下,可见其被剔除了layout外壳和数据描述,同时根布局被加上了
android:tag="layout/activity_main_0"


activity_main-layout.xml
app/build/intermediates/data_binding_layout_info_type_merge/debug/mergeDebugResources/out/
目录下,里面可以看到TextView被设置了一个
tag="binding_1"


                    false

接下来跟进具体实现类

ActivityMainBindingImpl

//ActivityMainBindingImpl.java
public ActivityMainBindingImpl(androidx.databinding.DataBindingComponent bindingComponent,View root) {
    this(bindingComponent, root, mapBindings(bindingComponent, root, 2, sIncludes, sViewsWithIds));
    //mapBindings会解析xml里data binding相关的tag,返回Object[]
    //如:if (isRoot && tag != null && tag.startsWith("layout"))
    //如:if (tag != null && tag.startsWith("binding_"))
}
private ActivityMainBindingImpl(androidx.databinding.DataBindingComponent bindingComponent, View root, Object[] bindings) {
    //bindings存储了布局文件里含tag的view,如bindings[0]是根布局,bindings[1]是TextView
    //调用父类ActivityMainBinding的构造方法,为TextView赋值
    super(bindingComponent, root, 0, (android.widget.TextView) bindings[1]);
    this.mboundView0 = (android.widget.ScrollView) bindings[0];
    //这里把tag置空,就不会影响到开发者自己写的tag
    this.mboundView0.setTag(null);
    this.tvName.setTag(null);
    setRootTag(root);
    invalidateAll();
}
//省略调用链:invalidateAll -> requestRebind -> mUIThreadHandler.post(mRebindRunnable);
// -> executePendingBindings -> executeBindingsInternal -> executeBindings
@Override
protected void executeBindings() {
    long dirtyFlags = 0;
    synchronized(this) {
        dirtyFlags = mDirtyFlags;
        mDirtyFlags = 0;
    }
    java.lang.String userName = null;
    com.holiday.jetpackstudy.model.User user = mUser;
    if ((dirtyFlags & 0x3L) != 0) {
        //这里对数据进行了判空,避免了空指针
        if (user != null) {
            userName = user.getName();
        }
    }
    if ((dirtyFlags & 0x3L) != 0) {
        //这里把数据设置给了TextView
        androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tvName, userName);
    }
}

最后补充一点,

ActivityMainBinding
这个类的位置在
app/build/generated/data_binding_base_class_source_out/debug/dataBindingGenBaseClassesDebug/out/$业务包名/databinding/
路径下,从这里可以找到binding能直接引用view的原因:

//ActivityMainBinding.java
public abstract class ActivityMainBinding extends ViewDataBinding {
    public final TextView tvName;
    protected ActivityMainBinding(Object _bindingComponent, View _root, int _localFieldCount,TextView tvName) {
        super(_bindingComponent, _root, _localFieldCount);
        this.tvName = tvName;
    }
}
优缺点 优点: DataBinding会对绑定的数据进行判空,减少判空代码和空指针异常 省去了找id操作,不会再出现id找不着的情况 缺点: apt创建了很多类,增大包体积和编译时长 参考文章 简书-Android中的DataBinding的原理浅析

哈利迪 原创文章 5获赞 0访问量 76 关注 私信 展开阅读全文
作者:哈利迪


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯