关闭

Data Binding

标签: Data Binding
258人阅读 评论(0) 收藏 举报
分类:
第一步 配置
在build.gradle文件
android {
   
....
    dataBinding
{
        enabled
=true
   
}
}

第二步 编写Data Binding布局文件
<?xml version="1.0" encoding="utf-8"?>
<layoutxmlns:android="http://schemas.android.com/apk/res/android">
   
<data>
       
<variablename="user"type="com.example.User"/>
   
</data>
   
<LinearLayout
       
android:orientation="vertical"
       
android:layout_width="match_parent"
       
android:layout_height="match_parent">
   
</LinearLayout>
</layout>
<variable/> 用来声明变量,name变量名字,type类型包名+类名
使用:@{user.username},会调用user.getUsername方法或username()方法
<TextViewandroid:text="@{user.username}"
第三步  Binding Data
     Data Binding布局文件,会生成布局文件名对应的类,例如:main_activity.xml,生成MainActivityBinding类,如果<data/>没有子标签,不会生成
   
   在onCreate方法中,不要调用setContentView,用下面代码替代
    MainActivityBinding binding =DataBindingUtil.setContentView(this, R.layout.main_activity);
   
User user =newUser("Test","User");
    binding
.setUser(user);
   可以这样
MainActivityBinding binding =MainActivityBinding.inflate(getLayoutInflater());
如果布局文件,包括ListView,RecyclerView
ListItemBinding binding =ListItemBinding.inflate(layoutInflater, viewGroup,false);
//or
ListItemBinding binding =DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup,false);
Binding Events
    和绑定数据差不多
publicclass ButtonHandler{
   
publicvoid click(View view){...}
}
<variablename="handler"type="com.example.Handler"/>
<Button android:onClick="@{handlers.click}"/>
特殊点击事件

Data Binding 布局详解
    Imports:引入类,像Java一样引入类。
<data>
   
<importtype="android.view.View"/>
</data>
<TextViewandroid:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>
    如果引入多个相同类名,可以使用alias指定别名
<importtype="com.example.real.estate.View"alias="Vista"/>
    集合,后面User表示泛型
<variablename="userList"type="List&lt;User>"/>
    引入静态field或方法

    java.lang.* 里的类自动引入

Variables
    有个默认的context变量,被binding表达式使用。root View的getContext()。如果声明了context变量,覆盖功能就不起作用。

自定义生成Binding Class名字
    <dataclass="ContactItem"</data>
    <data class=".ContactItem"> </data>
    <data class="com.demo.ContactItem"> </data>

Includes
    指定命名空间 xmlns:bind="http://schemas.android.com/apk/res-auto" ,name.xml必须有个user变量
   <LinearLayout>
       
<includelayout="@layout/name"bind:user="@{user}"/>
   
</LinearLayout>
   不支持
   <merge>
       
<includelayout="@layout/name"
           
bind:user="@{user}"/>
       
<includelayout="@layout/contact"
           
bind:user="@{user}"/>
   
</merge>

Expression Language
    有很多像Java expression
  • Mathematical + - / * %
  • String concatenation +
  • Logical && ||
  • Binary & | ^
  • Unary + - ! ~
  • Shift >> >>> <<
  • Comparison == > < >= <=
  • instanceof
  • Grouping ()
  • Literals - character, String, numeric, null
  • Cast
  • Method calls
  • Field access
  • Array access []
  • Ternary operator ?:
    没有的操作
  • this
  • super
  • new
  • Explicit generic invocation
  Null Coalescing Operator (??)
    空操作,左边表达式不空时,使用左边表达式值,否则使用右边表达式值
    android:text="@{user.displayName ?? user.lastName}"

避免空指针错误
    @{user.name} 如果user为空,那么user.name为null,基本类型是默认值

集合,array,list,map可以使用[] 操作符访问
android:text="@{list[index]}"
android:text="@{map[key]}"
字符串,可以使用单双引号交替,就像前端那种写法
android:text='@{map["firstName"]}'
Resources
android:text="@{@string/nameFormat(firstName, lastName)}"
后面firstName,lastName是参数,等于调用getResources.getString(R.string.nameFormat, firstName, lastName);
Type Normal Reference Expression Reference
String[] @array @stringArray
int[] @array @intArray
TypedArray @array @typedArray
Animator @animator @animator
StateListAnimator @animator @stateListAnimator
color int @color @color
ColorStateList @color @colorStateList

Data Objects
    Data Binding 使用的POJO对象,POJO对象改变,不会通知UI更新的。Data Binding提供三种数据改变通知机制:
Observalbe Objects
    Observable 接口有增加和移除listener方法,通过变换由开发者调用,可以继承它的子类BaseObservable.
    在getter方法上添加@Bindable注解,该注解在编译时生成BR类,在module package默认根包下
    在setter通知数据变化notifyPropertyChanged(BR.firstName);
ObservableFields
publicfinalObservableField<String> sex =newObservableField<>();
使用:
<TextView android:text="@{user.sex}"/>
user.sex.set("男");
int age = user.age.get();
Observable Collections
    把原来使用的集合类,换成下面这种
ObservableArrayMap<String,Object> user =newObservableArrayMap<>();
ObservableArrayList<String> lists = new ObservableArrayList<>();
生成 Binding

创建
MyLayoutBinding binding =MyLayoutBinding.inflate(layoutInflater);
MyLayoutBinding binding =MyLayoutBinding.inflate(layoutInflater, viewGroup,false);
MyLayoutBinding binding =MyLayoutBinding.bind(viewRoot);
ViewDataBinding binding =DataBindingUtil.inflate(LayoutInflater, layoutId,
    parent
, attachToParent);
ViewDataBinding binding =DataBindingUtil.bindTo(viewRoot, layoutId);
根据Id生成View对象
    这机制比findViewById更快
<TextView
android:id="@+id/username"/>

<TextView
android:id="@+id/userAge"/>

变量
    每个变量都提供访问方法
ViewStubs
        当viewstub inflate布局时,binding需要为新的布局重新创建,ViewStubProxy监听ViewStub'sViewStub.OnInflateListener并及时创建binding,ViewStubProxy允许开发者设置OnInflateListener,并创建binding

Advanced Binding
    binding class需要动态生成,例如RecyclerView.Adapter,在Holder提供getBinding方法返回Binding对象
publicvoid onBindViewHolder(BindingHolder holder,int position){
   
final T item = mItems.get(position);
   holder
.getBinding().setVariable(BR.item, item);
   holder
.getBinding().executePendingBindings();
}
   变量数据变化时,binding将会下一帧改变,如果需要立即执行,调用 executePendingBindings()方法
   只要不是集合变量数据,可以后台线程进行修改数据值,不用担心同步问题。Data binding will localize each variable / field
Attribute Setters
    对于一个属性,data binding尽量找setAttribute方法,命名空间不重要,主要是属性名字
    例如:DrawerLayout 没有任何属性,但提供大量的setter方法,所有能这样使用。
<android.support.v4.widget.DrawerLayout
    app:scrimColor="@{@color/scrim}"
   
app:drawerListener="@{fragment.drawerListener}"/>
Renamed Setters
    更改属性关联的setter方法,替换原来的setter方法,通过BindingMethods注解关联一个setter方法,
@BindingMethods({
       
@BindingMethod(type ="android.widget.ImageView",
                      attribute
="android:tint",
                      method
="setImageTintList"),
})
Custom Setters
    有的属性需要自定义binding逻辑,例如:android:paddingLeft没有对应的setter方法,只存在setPadding(left, top, right, bottom)
@BindingAdapter("android:paddingLeft")
public static void setPaddingLeft(View view,int padding){
   view
.setPadding(padding,
                   view
.getPaddingTop(),
                   view
.getPaddingRight(),
                   view
.getPaddingBottom());
}
接受多个参数
@BindingAdapter({"bind:imageUrl","bind:error"})
public static void loadImage(ImageView view,String url,Drawable error){
   
Picasso.with(view.getContext()).load(url).error(error).into(view);
}
<ImageViewapp:imageUrl=“@{venue.imageUrl}”
app:error=“@{@drawable/venueError}”/>
Binding adapter接受属性的old value
@BindingAdapter("android:paddingLeft")
publicstaticvoid setPaddingLeft(View view,int oldPadding,int newPadding){
   
if(oldPadding != newPadding){
       view
.setPadding(newPadding,
                       view
.getPaddingTop(),
                       view
.getPaddingRight(),
                       view
.getPaddingBottom());
   
}
}
事件处理只有一个抽象方法的接口或抽象类
@BindingAdapter("android:onLayoutChange")
publicstaticvoid setOnLayoutChangeListener(View view,View.OnLayoutChangeListener oldValue,
       
View.OnLayoutChangeListener newValue){
   
if(Build.VERSION.SDK_INT >=Build.VERSION_CODES.HONEYCOMB){
       
if(oldValue !=null){
            view
.removeOnLayoutChangeListener(oldValue);
       
}
       
if(newValue !=null){
            view
.addOnLayoutChangeListener(newValue);
       
}
   
}
}
事件处理有多个抽象方法的接口或抽象类,例如View.OnAttachStateChangeListener
@BindingAdapter("android:onViewAttachedToWindow")
public static void setListener(View view, OnViewAttachedToWindow attached) {
    setListener
(view, null, attached);
}

@BindingAdapter("android:onViewDetachedFromWindow")
public static void setListener(View view, OnViewDetachedFromWindow detached) {
    setListener
(view, detached, null);
}

@BindingAdapter({"android:onViewDetachedFromWindow", "android:onViewAttachedToWindow"})
public static void setListener(View view, final OnViewDetachedFromWindow detach,
       
final OnViewAttachedToWindow attach) {
   
if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB_MR1) {
       
final OnAttachStateChangeListener newListener;
       
if (detach == null && attach == null) {
            newListener
= null;
       
} else {
            newListener
= new OnAttachStateChangeListener() {
               
@Override
               
public void onViewAttachedToWindow(View v) {
                   
if (attach != null) {
                        attach
.onViewAttachedToWindow(v);
                   
}
               
}

               
@Override
               
public void onViewDetachedFromWindow(View v) {
                   
if (detach != null) {
                        detach
.onViewDetachedFromWindow(v);
                   
}
               
}
           
};
       
}
       
final OnAttachStateChangeListener oldListener = ListenerUtil.trackListener(view,
                newListener
, R.id.onAttachStateChangeListener);
       
if (oldListener != null) {
            view
.removeOnAttachStateChangeListener(oldListener);
       
}
       
if (newListener != null) {
            view
.addOnAttachStateChangeListener(newListener);
       
}
   
}
}

Converters
  Object Conversions 对象转换
<TextView   android:text='@{userMap["lastName"]}'/>
userMap返回的对象,会传进setText(CharSequence)方法当为参数
  Custom Conversions
@{}返回的类型和android属性需要类型不一样时,可以是Conversions进行转换
<Viewandroid:background="@{isError ? @color/red : @color/white}"/>
在binding activity添加下面代码
@BindingConversion
publicstaticColorDrawable convertColorToDrawable(int color){
   
returnnewColorDrawable(color);
}
不允许混合类型
<Viewandroid:background="@{isError ? @drawable/error : @color/white}"/>
Android Studio Support for Data Binding
  • Syntax highlighting
  • Flagging of expression language syntax errors
  • XML code completion
  • References, including navigation (such as navigate to a declaration) and quick documentation
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:11703次
    • 积分:314
    • 等级:
    • 排名:千里之外
    • 原创:19篇
    • 转载:0篇
    • 译文:1篇
    • 评论:1条
    文章分类