使用databinding

目录

配置

简单使用

 先生成java bean类,User

xml文件

 activity

高级使用

import type

布局文件中对data数据的引用

 基本数据类型

 @{}包裹内容还支持运算符

事件绑定

方式1

方式2

方式3

自定义属性

数据刷新

第一种:JavaBean继承BaseObservable

第二种:JavaBean中字段改为ObservableField 

第三种:不使用JavaBean,创建Observable Clollections ;

数据转换

自行转换

自动转换 

列表适配器

ListView的适配器使用Databinding:

RecyclerView的适配器

使用Databinding:


配置

DataBinding的应用需要在android4.0(API14)及以上版本 
首先需要在build.gradle文件中配置环境

android {
    ...
    dataBinding {
        enabled = true
    }
}

简单使用

 先生成java bean类,User

xml文件

正常DataBinDing绑定到xml中的数据格式是,以layout标签为根,首先添加data标签,绑定数据,代码如下:【代码来源】

   

<?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
       <data>
           <variable name="user" type="com.example.User"/>
       </data>
       <LinearLayout
           android:orientation="vertical"
           android:layout_width="match_parent"
           android:layout_height="match_parent">
           <TextView android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="@{user.firstName}"/>
           <TextView android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="@{user.lastName}"/>
       </LinearLayout>
    </layout>

 activity

在Activity中DataBinding调用xml有两种方式,一种是通过DataBingdingUtil调用xml文件名:

 

  @Override
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
       User user = new User("Test", "User");
       binding.setUser(user);
    }


第二种是直接通过LayoutInflater隐式的生成:

   

ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());


1
第三种:如果View已经被生成,需要重新绑定到Binding时可以调用如下: 

MyLayoutBinding binding = MyLayoutBinding.bind(viewRoot); 


如果是在Fragment、ListView、Recyclerview中则可以通过以下两种方式调用:   

 ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);

    ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);


注意:DataBinding绑定xml并自动生成Bingding文件的名称,是根据你定义xml文件的文件名称自动生成的,例如:你定义了一个activity_main.xml的文件,那么自动绑定完成之后生成的Binding文件名就是ActivityMainBinding.java
 

高级使用

import type

<data>

    <import type="com.test.qby.newtestapplication.model.TestModel"/>
    \\别名
    <import type="com.test.qby.newtestapplication.model.TestModel" alias="Model222"/>

    <variable
        name="test"
        type="TestModel" />

</data>

布局文件中对data数据的引用

android:text="@{@string/test+test.name}"

@{TestModel.getName()},但是需要getName()为static方法

 基本数据类型

<data>
    <variable  
        name="array"  
        type="String[]" /> 
    <variable
        name="list"
        type="java.util.ArrayList&lt;String&gt;" />
    <variable
        name="map"
        type="java.util.HashMap&lt;String,String&gt;" />
    <variable  
        name="arrayIndex"  
        type="int" />  
    <variable  
        name="listIndex"  
        type="int" />  
    <variable  
        name="key"  
        type="String" />  
</data>
<LinearLayout  
    android:orientation="vertical"  
    style="@style/MathchMathch"> 
    <TextView  
        style="@style/MatchWrap" 
        android:text="@{array[arrayIndex]}"/>   
    <TextView  
        style="@style/MatchWrap"
        android:text="@{list[listIndex]}"/>  
    <TextView  
        style="@style/MatchWrap" 
        android:text="@{map[key]}"/>  
</LinearLayout> 

 @{}包裹内容还支持运算符

“A??B”表示对前面字符串A是否为空的判断,如果为空,不显示,否则显示后面的字符串B,这里空判断包括null和字符串trim()之后为”“的判断。(就是说纯空格的字符串也是会作为空处理的) 

<data>

    <variable
            name="str"
            type="String"/>
    <variable
            name="error"
            type="boolean"/>

</data>

<LinearLayout 
    style="@style/MatchMatch"
    android:orientation="vertical">

    <TextView
            。。。
            android:text='@{error ?"error": "没错"}'
            。。。 />
        <TextView
            。。。
            android:text='@{str ?? str}'
            。。。 />

</LinearLayout >

 

android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>

事件绑定

方式1

<variable
    name="testClick"
    type="android.view.View.OnClickListener" />
...
//在控件中添加点击事件
android:onClick="@{testClick}"

代码调用

binding.setTestClick(view -> Log.e(TAG, "点击测试"));

方式2

导入处理类、引用处理类的方法

<variable
    name="mHandler"
    type="com.test.qby.newtestapplication.listener.MyHandler" />
...
android:onClick="@{view->mHandler.testClick(view)}"

方式3

android:onClick="@{mHandler::testClick}"

新建事件的处理类

/**
 * Created by qby on 2018/1/30 0030.
 * 事件处理类
 */

public class MyHandler {
    private static final String TAG = "MyHandler";

    public void testClick(View view){
        Log.e(TAG,"点击测试");
    }
}

在页面调用

binding.setMHandler(new MyHandler());

 

这样写,适用于多个页面点击事件执行代码一样的情况,因为执行代码是写在MyHandler的testClick中的。 
如果想执行不同代码,可以重写方法 
或者(如下) 
2、将MyHandler改为接口

/**
 * Created by qby on 2018/1/30 0030.
 * 事件处理接口
 */

public interface MyHandler {

    void testClick(View view);
}


在页面调用

binding.setMHandler(view -> Log.e(TAG, "点击测试"));

自定义属性

Databinding提供了@BindingAdapter(“属性名”)注解来完成自定义属性。 
在JavaBean中定义如下方法:

@BindingAdapter("show")
public static void showIcon(ImageView iv, String imgUrl) {
    if (!TextUtils.isEmpty(imgUrl)) {
        Glide.with(iv)
                .load(imgUrl)
                .into(iv);
    }
}

布局中引用时记得先加上自定义命名空间

xmlns:app="http://schemas.android.com/apk/res-auto"

在控件中使用

<ImageView
     style="@style/WrapWrap"
     app:show="@{test.url}"/>

代码调用

页面中调用方式也有几种
 

\\1
ActivityMainTestBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main_test);
\\2
View inflate = LayoutInflater.from(this).inflate(R.layout.activity_main_test, null);
ActivityMainTestBinding bind = DataBindingUtil.bind(inflate);
\\3
ActivityMainTestBinding inflate = DataBindingUtil.inflate(LayoutInflater.from(this), R.layout.activity_main_test, null, false);

 

数据刷新

第一种:JavaBean继承BaseObservable

public class TestModel extends BaseObservable{
    private String name;

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

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

}

 JavaBean继承BaseObservable;getter方法添加@Bindable注解;settter方法内部添加通知notifyPropertyChanged;

第二种:JavaBean中字段改为ObservableField 


Databinding提供的类包括:ObservableField,ObservableBoolean,ObservableByte,ObservableChar,ObservableShort,ObservableInt,ObservableLong,ObservableFloat,ObservableDouble,ObservableParcelable。

public class TestModel {
    public ObservableField<String> name = new ObservableField<>();
    public ObservableBoolean name = new ObservableBoolean();
}

别忘了字段修饰符要public,调用直接使用set()

TestModel testModel = new TestModel();
testModel.name.set("这是测试文字");
testModel.isTrue.set(true);

 

布局中引用方式与其他的没区别,在代码中获取值就直接调用get()

String name = testModel.name.get();
boolean isTrue = testModel.isTrue.get();


这种方法虽然看着没有getter/setter方法,但是它是在内部实现过了。
 

第三种:不使用JavaBean,创建Observable Clollections ;


这种方式是为了不创建Javabean,而使用动态数据结构来更新UI。Databinding提供了ObservableArrayMap,ObservableArrayList两个类来实现。 
使用代码动态创建

ObservableArrayList<Object> observableList = new ObservableArrayList<>();
observableList.add("databindingList");
observableList.add(12);
binding.setListIndex(1);
binding.setObservableList(observableList);

ObservableArrayMap<String,Object> observableMap = new ObservableArrayMap<>();
observableMap.put("hash1", "databindingMap");
observableMap.put("hash2", 16);
observableMap.put("hash3", "显示");
binding.setKey("hash3");
binding.setObservableMap(observableMap);

使用方式跟使用ArrayList、HashMap没什么区别

<data>

    <variable
        name="list"
        type="android.databinding.ObservableArrayList&lt;Object&gt;" />
    <variable
        name="map"
        type="android.databinding.ObservableArrayMap&lt;String,Object&gt;" /> 
    <variable  
        name="listIndex"  
        type="int" />  
    <variable  
        name="key"  
        type="String" />  
</data>
<LinearLayout  
    android:orientation="vertical"  
    style="@style/MathchMathch"> 
    <TextView  
        style="@style/MatchWrap"
        android:text="@{String.valueOf(list[listIndex])}"/>  
    <TextView  
        style="@style/MatchWrap" 
        android:text="@{String.valueOf(map[key])}"/>  
</LinearLayout> 

数据转换

自行转换

在布局中引用的数据,如果要求的类型与获取的类型不一致,需要开发者自行转换。 
android:text=”要求是CharSequence类型”,使用String.valueOf()转换; 
还有一种非常实用的转换:

<TextView
     style="@style/WrapWrap"
     android:text="@{String.valueOf(observableMap[key])}"
     android:visibility="@{error?android.view.View.VISIBLE:android.view.View.INVISIBLE}"
     android:textColor="@{error?@color/red:@color/green}"
     android:background="@{error?@color/green:@color/red}"
     />

这里根据error是否为true,判断了TextView的显示隐藏、背景以及文字的颜色。 
android:visibility中可以将android.view.View使用import导包,写成

//data节点下
<import type="android.view.View"/>
//引用
android:visibility="@{error?View.VISIBLE:View.INVISIBLE}"

注意同一属性只能引用同种类型的数据,即android:background中error为true/false,引用@color只能引用@color,引用@drawable只能引用@drawable,不能同时@color和@drawable混用(可能你混用还是能运行,但是一改变error的值切换的时候就会“嘣嘣嘣”了)。

自动转换 


Databinding提供了自

目录

配置

简单使用

 先生成java bean类,User

xml文件

 activity

高级使用

import type

布局文件中对data数据的引用

 基本数据类型

 @{}包裹内容还支持运算符

事件绑定

方式1

方式2

方式3

自定义属性

数据刷新

第一种:JavaBean继承BaseObservable

第二种:JavaBean中字段改为ObservableField 

第三种:不使用JavaBean,创建Observable Clollections ;

数据转换

自行转换

自动转换 

列表适配器

ListView的适配器使用Databinding:

RecyclerView的适配器

使用Databinding:


动转换注解@BindingConversion,还是来个栗子:

布局:

<variable
     name="time"
     type="java.util.Date"/>

<TextView
     style="@style/WrapWrap"
     android:text="@{time}"/>


代码:

binding.setTime(new Date());

直接运行,当然会报错,关键在这:

/**
 * Created by qby on 2018/1/31 0031.
 * 自动转换器
 */

public class MyDateConverter {

    @BindingConversion
    public static String convertDate(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);
        return sdf.format(date);
    }

}

列表适配器

ListView的适配器使用Databinding:

public class MyListViewAdapter<T> extends BaseAdapter {
    private LayoutInflater inflater;
    private int layoutId;
    private int variableId;
    private List<T> list;

    public FutureWeatherAdapter(Context context, int layoutId, List<T> list, int resId) {
        this.layoutId = layoutId;
        this.list = list;
        this.variableId = resId;
        inflater = LayoutInflater.from(context);
    }

    @Override

    public int getCount() {
        return list.size();
    }

    @Override
    public Object getItem(int position) {
        return list.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewDataBinding dataBinding;
        if (convertView == null) {
            dataBinding = DataBindingUtil.inflate(inflater, layoutId, parent, false);
        } else {
            dataBinding = DataBindingUtil.getBinding(convertView);
        }
        dataBinding.setVariable(variableId, list.get(position));
        return dataBinding.getRoot();
    }
}

 

dataBinding.getRoot()获取到的就是convertView;dataBinding.setVariable跟上面在页面写的binding.setTime一样,只不过setTime是因为已经转换成特定唯一的ActivityMainTestBinding,内部也是调用的setVariable,因为这个是公共ListView适配器,只能获取到抽象类ViewDataBinding,所以只能使用setVariable。variableId就相当于BR.time,这里与条目布局文件需要的对象一致。 
例如 条目布局中:

<variable
     name="test"
     type="com.test.qby.newtestapplication.model.TestModel" />

RecyclerView的适配器

使用Databinding:

public class MyRecyclerViewAdapter<T> extends RecyclerView.Adapter {

    private LayoutInflater inflater;
    private int layoutId;
    private int variableId;
    private List<T> list;

    public MyRecyclerViewAdapter(Context context, int layoutId, List<T> list, int resId) {
        this.layoutId = layoutId;
        this.list = list;
        this.variableId = resId;
        inflater = LayoutInflater.from(context);
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        ViewDataBinding binding = DataBindingUtil.inflate(inflater, layoutId, viewGroup, false);
        return new MyViewHolder(binding);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof MyViewHolder) {
            MyViewHolder holder1 = (MyViewHolder) holder;
            holder1.getBinding().setVariable(variableId, list.get(position));
            holder1.getBinding().executePendingBindings();
        }
    }

    @Override
    public int getItemCount() {
        return list.size();
    }

    public static class MyViewHolder extends RecyclerView.ViewHolder {

        private ViewDataBinding binding;

        public MyViewHolder(ViewDataBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }

        public ViewDataBinding getBinding() {
            return this.binding;
        }
    }
}


Databinding在RecyclerView中的使用跟ListView中基本一样,出现了一个executePendingBindings方法是因为:

当数据改变时,binding会在下一帧去改变数据,如果我们需要立即改变,就去调用executePendingBindings方法。

在这里的作用就是让改变数据立即执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值