美文网首页
Jetpack-DataBinding

Jetpack-DataBinding

作者: 内卷程序员 | 来源:发表于2021-09-01 15:57 被阅读0次

DataBinding概述

  • DataBinding主要是将数据与UI控件的绑定,你无需手动调用视图来 set 新状态,你只需 set 数据本身。
  • 使用方式可以参考https://www.jianshu.com/p/a294e1ea3327

DataBinding使用方式

1、在主Module的build.gradle android模块中添加配置

android {

    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "xxxxx"
        minSdkVersion 16
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        //使用databinding
        dataBinding{
            enabled true
        }

   新版本使用
    buildFeatures {
        dataBinding = true
    }
    }

定义模型

public class User  {
    private String name;
    private String pwd;

    public User(String name, String pwd) {
        this.name = name;
        this.pwd = pwd;
    }

    @Bindable
    public String getName() {
        return name;
    }

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

    @Bindable
    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
}

修改布局文件

<?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">
    <!--这里面就用来定义数据源-->
    <data>
        <variable
            name="user"
            type= "com.example.ysj.User"/>
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:textSize="50sp"
            android:id="@+id/tv1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.name}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:textSize="50sp"
            android:id="@+id/tv2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.pwd}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </LinearLayout>

</layout>

在Activity设置DataBinding


public class MainActivity extends AppCompatActivity {
    ActivityMainBinding binding;
    //从model层来的数据
    User user;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.activity_main);
        //完成UI初始化
        binding= DataBindingUtil.setContentView(this,R.layout.activity_main);
        user=new User("测试用户","123456");
        //设置值
        binding.setUser(user);
        
    }
}

更多详细使用可以参考以下网址

https://www.jianshu.com/p/70316eb4e0f8

DataBinding原理 DataBindingUtil.setContentView

布局文件会被解析拆分成两个布局文件

//这个文件主要是记录布局文件基本信息并将布局文件每个组件都包装成Target 
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Layout directory="layout" filePath="app\src\main\res\layout\activity_main.xml"
    isBindingData="true" isMerge="false" layout="activity_main"
    modulePackage="com.example.databindingdemo_20210117" rootNodeType="android.widget.LinearLayout">
    <Variables name="user" declared="true" type="com.example.ysj.User">
        <location endLine="8" endOffset="41" startLine="6" startOffset="8" />
    </Variables>
    <Targets>
        <Target tag="layout/activity_main_0" view="LinearLayout">
            <Expressions />
            <location endLine="38" endOffset="18" startLine="11" startOffset="4" />
        </Target>
        <Target id="@+id/tv1" tag="binding_1" view="TextView">
            <Expressions>
                <Expression attribute="android:text" text="user.name">
                    <Location endLine="21" endOffset="38" startLine="21" startOffset="12" />
                    <TwoWay>false</TwoWay>
                    <ValueLocation endLine="21" endOffset="36" startLine="21" startOffset="28" />
                </Expression>
            </Expressions>
            <location endLine="25" endOffset="55" startLine="16" startOffset="8" />
        </Target>
        <Target id="@+id/tv2" tag="binding_2" view="TextView">
            <Expressions>
                <Expression attribute="android:text" text="user.pwd">
                    <Location endLine="32" endOffset="37" startLine="32" startOffset="12" />
                    <TwoWay>false</TwoWay>
                    <ValueLocation endLine="32" endOffset="35" startLine="32" startOffset="28" />
                </Expression>
            </Expressions>
            <location endLine="36" endOffset="55" startLine="27" startOffset="8" />
        </Target>
    </Targets>
</Layout>

//第二个布局文件就通过tag和第一个布局文件关联

<?xml version="1.0" encoding="utf-8"?>

<!--这里面就用来定义数据源-->


<LinearLayout 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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:tag="layout/activity_main_0">

    <TextView
        android:id="@+id/tv1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:tag="binding_1"
        android:textSize="50sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tv2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:tag="binding_2"
        android:textSize="50sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</LinearLayout>
public class DataBindingUtil {

private static DataBinderMapper sMapper = new DataBinderMapperImpl();

public static <T extends ViewDataBinding> T setContentView(@NonNull Activity activity,
            int layoutId, @Nullable DataBindingComponent bindingComponent) {
        //设置布局文件
        activity.setContentView(layoutId);
        View decorView = activity.getWindow().getDecorView();
        //获取contentView 布局文件
        ViewGroup contentView = (ViewGroup) decorView.findViewById(android.R.id.content);
        return bindToAddedViews(bindingComponent, contentView, 0, layoutId);
    }

  private static <T extends ViewDataBinding> T bindToAddedViews(DataBindingComponent component,
            ViewGroup parent, int startChildren, int layoutId) {
        final int endChildren = parent.getChildCount();
        final int childrenAdded = endChildren - startChildren;
        if (childrenAdded == 1) {
            final View childView = parent.getChildAt(endChildren - 1);
            return bind(component, childView, layoutId);
        } else {
            final View[] children = new View[childrenAdded];
            for (int i = 0; i < childrenAdded; i++) {
                children[i] = parent.getChildAt(i + startChildren);
            }
            return bind(component, children, layoutId);
        }
    }
    static <T extends ViewDataBinding> T bind(DataBindingComponent bindingComponent, View[] roots,
            int layoutId) {
          //DataBinderMapperImpl 
        return (T) sMapper.getDataBinder(bindingComponent, roots, layoutId);
    }

    static <T extends ViewDataBinding> T bind(DataBindingComponent bindingComponent, View root,
            int layoutId) {

        return (T) sMapper.getDataBinder(bindingComponent, root, layoutId);
    }
}
···

//类似map映射

public class DataBinderMapperImpl extends DataBinderMapper {
  private static final int LAYOUT_ACTIVITYMAIN = 1;
   //映射对象,里面存了布局文件解析后的key(布局文件)和value(编号)
  private static final SparseIntArray INTERNAL_LAYOUT_ID_LOOKUP = new SparseIntArray(1);

  static {
    INTERNAL_LAYOUT_ID_LOOKUP.put(com.example.databindingdemo_20210117.R.layout.activity_main, LAYOUT_ACTIVITYMAIN);
  }

  @Override
  public ViewDataBinding getDataBinder(DataBindingComponent component, View view, int layoutId) {
   //通过传进来的layoutId,解析对应的tag,然后从映射里面找对应的布局文件,然后找到了就新建对应的ViewDatabinding对象,然后返回
    int localizedLayoutId = INTERNAL_LAYOUT_ID_LOOKUP.get(layoutId);
    if(localizedLayoutId > 0) {
      final Object tag = view.getTag();
      if(tag == null) {
        throw new RuntimeException("view must have a tag");
      }
      switch(localizedLayoutId) {
        case  LAYOUT_ACTIVITYMAIN: {
          if ("layout/activity_main_0".equals(tag)) {
            return new ActivityMainBindingImpl(component, view);
          }
          throw new IllegalArgumentException("The tag for activity_main is invalid. Received: " + tag);
        }
      }
    }
    return null;
  }
}
public class ActivityMainBindingImpl extends ActivityMainBinding  {

//解析对应的组件然后放到数组里面
 public ActivityMainBindingImpl(@Nullable androidx.databinding.DataBindingComponent bindingComponent, @NonNull View root) {
        this(bindingComponent, root, mapBindings(bindingComponent, root, 3, sIncludes, sViewsWithIds));
    }
    private ActivityMainBindingImpl(androidx.databinding.DataBindingComponent bindingComponent, View root, Object[] bindings) {
        super(bindingComponent, root, 1
            , (android.widget.TextView) bindings[1]
            , (android.widget.TextView) bindings[2]
            );
       //为每个组件设置tag
        this.mboundView0 = (android.widget.LinearLayout) bindings[0];
        this.mboundView0.setTag(null);
        this.tv1.setTag(null);
        this.tv2.setTag(null);
        setRootTag(root);
        // listeners
        invalidateAll();
    }
}
}

到此时DataBindingUtil 的 setContentView方法分析完毕

DataBinding原理 DataBindingUtil.setData

    public void setUser(@Nullable com.example.ysj.User User) {
       //更新监听注册
        updateRegistration(0, User);
        this.mUser = User;
        synchronized(this) {
            mDirtyFlags |= 0x1L;
        }
        notifyPropertyChanged(BR.user);
        super.requestRebind();
    }


public abstract class ViewDataBinding extends BaseObservable implements ViewBinding {

    ...

     //创建监听器类
    private static final CreateWeakListener CREATE_PROPERTY_LISTENER = new CreateWeakListener() {
        @Override
        public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) {
            //创建属性监听器,当属性发生改变的时候可以被监听
            return new WeakPropertyListener(viewDataBinding, localFieldId).getListener();
        }
    };

     //更新监听注册,localFieldId为BR中的ID,它会为每一个属性生成一个编号
    protected boolean updateRegistration(int localFieldId, Observable observable) {
        return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER);
    }

    private boolean updateRegistration(int localFieldId, Object observable,
            CreateWeakListener listenerCreator) {
        if (observable == null) {
            return unregisterFrom(localFieldId);
        }
        WeakListener listener = mLocalFieldObservers[localFieldId];
        if (listener == null) {
            registerTo(localFieldId, observable, listenerCreator);
            return true;
        }
        if (listener.getTarget() == observable) {
            return false;//nothing to do, same object
        }
        unregisterFrom(localFieldId);
        registerTo(localFieldId, observable, listenerCreator);
        return true;
    }

  protected void registerTo(int localFieldId, Object observable, ViewDataBinding.CreateWeakListener listenerCreator) {
        if (observable != null) {
            ViewDataBinding.WeakListener listener = this.mLocalFieldObservers[localFieldId];
            if (listener == null) {
                listener = listenerCreator.create(this, localFieldId);
                this.mLocalFieldObservers[localFieldId] = listener;
                if (this.mLifecycleOwner != null) {
                    listener.setLifecycleOwner(this.mLifecycleOwner);
                }
            }
            listener.setTarget(observable);
        }
    }
}



相关文章

  • Jetpack-DataBinding

    DataBinding DataBinding是一个支持库,顾名思义:数据绑定,它可以将布局页面中的组件与应用中的...

  • Jetpack-DataBinding

    DataBinding概述 DataBinding主要是将数据与UI控件的绑定,你无需手动调用视图来 set 新状...

  • 01 Jetpack-DataBinding

    一、DataBinding简介 在传统的Android应用开发中,布局文件通常只负责应用界面的布局工作,如果需要实...

  • JetPack-DataBinding 简单使用

    1.开启 2.布局和Bean 创建普通布局后,鼠标选中根布局,alt+enter 提示,convert to Da...

  • Jetpack-DataBinding初体验

    上一次中的代码: 利用DataBinding改善 首先再build.gradle中开启dadabinding 然后...

  • jetpack-DataBinding onClick 的几种点

    DataBinding onClick 的几种点击方式 1.@{click} 2.不带参数:@{() -> vie...

网友评论

      本文标题:Jetpack-DataBinding

      本文链接:https://www.haomeiwen.com/subject/cunxwltx.html