MVVM之DataBinding

来源:互联网 发布:java 链接生成二维码 编辑:程序博客网 时间:2024/05/21 01:54

参考自
Android官方数据绑定框架DataBinding(一)
Android官方数据绑定框架DataBinding(二)

  • 环境配置
    app模块的bulid.gradle下
    dataBinding{        enabled=true;    }

布局文件

  1. 以layout为根布局,并添加<data> 节点,这样layout里面就分为2部分,一部分就是data 一部分就是我们的布局。
  2. 在data里面绑定数据
<layout xmlns:android="http://schemas.android.com/apk/res/android">        <data>            <import type="com.example.gzp.mvvmtest.Student"/>            <variable                name="stu"                  type="student"/>        </data>        <LinearLayout            android:layout_width="match_parent"            android:layout_height="match_parent"            android:orientation="vertical">            <TextView                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:text="@{stu.name}"/>        </LinearLayout></layout>

导入了一个student类 里面有name,add 属性 和相应的get,set方法。
或者type="com.example.gzp.mvvmtest.Student" 不用import。
type 支持基本数据类型和集合(list,map等)类型,类

<variable    name="num"    type="int" /> <variable    name="list"    type="ArrayList&lt;String>"/>   

< 符号需要转义&lt;

       <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="@{map[`name`]}"/>

集合变量名[key]的形式使用,如果你的key是一个字面字符串可以使用反引号,也可以使用转义后的双引号。
android:text='@{map["name"]}'
android:text="@{map[&quot;name&quot;]}"


  • 取别名

如果import了两个相同名称的类

    <import type="com.example.gzp.mvvmtest.Student" alisa="mystu"/>    <import type="com.example.Student"/>
  • xml里还可以调用函数
    android:text="@{String.valueof(num)}"
  • 还可以调用表达式

    • 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
  • ??表达式
    android:text='@{str ?? "null"}'
    等价于
    android:text='@{str!=null ? str:"null"}'

java

ActivityMainBinding binding=
DataBindingUtil.setContentView(this,R.layout.activity_main);

ActivityMainBinding 自动生成的类,命名方法:
将我们布局文件的首字母大写,并且去掉下划线,将下划线后面的字母大写,加上Binding组成。

  • 自定义类
    在xml文件中
    <data class=".Custom">
    …..
    </data>
    包名.Custom binding=DataBindingUtil.XXXXXX();
    给对应的变量赋值
    binding=setXXXX;
    XXX为我们在布局文件定义的变量首字母大写
    binding.setStr("string");
    binding.setList(arrayList);
  • 获取实例
    当我们需要某个view的实例时,我们只要给该view一个id,然后Data Binding框架就会给我们自动生成该view的实例
    <TextView        android:id="@+id/textView"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="@{stu.name}"/>

mBinding.textView.setTextColor(Color.GREEN);
* 事件的绑定
……
<variable
name="handlers"
type="EventHandlers" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CLICK ME"
android:onClick="@{handlers.click}"/>
……

        binding.setHandler(new EventHandlers());

调用了EventHandlers里面的click(View view)方法。

  • 数据的同步
    @Bindable    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;        notifyPropertyChanged(包名.BR.name);    }

在get方法上加上注释@Bindable
在set方法里面添加notifyPropertyChanged(包名.BR.name);

在点击事件中修改数据,数据就会自动修改了

    public void click(View view) {        mStu.setName("ben");    }}
  • ObservableFields家族
    可以不需要定义get,set方法
    数据类型定义为:
    public ObservableField<String> name = new ObservableField<>();
    public ObservableInt age = new ObservableInt();
    Observable+基本数据类型的方式。

    • ObservableField
    • ObservableBoolean
    • ObservableByte
    • ObservableShort
    • ObservableInt
    • ObservableLong
    • ObservableDouble
    • ObservableParcelable
    • ObservableArrayMap
    • ObservableArrayList

    使用
    mPeople = new People();
    binding.setPeople(mPeople);
    mPeople.name.set("people");
    mPeople.age.set(19);
    mPeople.isMan.set(true);

......     <variable            name="str"            type="android.databinding.ObservableField&lt;String>" />     ......        <TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="@{str.get}"/>
ObservableArrayMap<String, String> map = new ObservableArrayMap<>();ObservableArrayList<String> list = new ObservableArrayList<>();map.put("name", "abc");list.add("hi");binding.setMap(map);binding.setList(list);
  • 在fragment中使用

    infate方法
    MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater);
    MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater, viewGroup, false);

     public View onCreateView(LayoutInflater inflater,                         ViewGroup container, Bundle savedInstanceState) {        包名.Custom binding = DataBindingUtil.inflate(inflater,            R.layout.frag_layout, container, false);    mStu = new Student(20, "abc");//getRoot可以获取我们加载的布局    return binding.getRoot();}
  • RecyclerView的使用
    private class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>{        private ArrayList<Student> mData = new ArrayList<>();        public MyAdapter(ArrayList<Student> data) {            mData = data;        }        @Override        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        //之前DataBindingUtil返回的那些都是ViewDataBinding的子类            ViewDataBinding binding=DataBindingUtil.inflate(LayoutInflater.from(getContext()), R.layout.recycler_view_item, parent, false);            //参数是item布局            ViewHolder holder=new ViewHolder(binding.getRoot());            //保存了刚刚返回的ViewDataBinding对象            holder.setBinding(binding);            return holder;        }        @Override        public void onBindViewHolder(ViewHolder holder, int position) {            holder.getBinding().setVariable(BR.stu, mData.get(position));            //当数据改变时,binding会在下一帧去改变数据,如果我们需要立即改变,就去调用executePendingBindings方法。            holder.getBinding().executePendingBindings();        }        @Override        public int getItemCount() {            return mData.size();        }         class ViewHolder extends RecyclerView.ViewHolder{            private ViewDataBinding mBinding;            public ViewHolder(View itemView) {                super(itemView);            }            public void setBinding(ViewDataBinding binding) {                this.mBinding=binding;            }            public ViewDataBinding getBinding() {                return  mBinding;            }        }    }}
  • 自定义setter
    • ImageView需要通过网络去加载图片
    • 格式化日期
<layout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto">    <data class=".Custom">        <variable            name="imageUrl"            type="String" />        <variable            name="time"            type="java.util.Date" />    </data>    <ImageView        android:layout_width="match_parent"        android:layout_height="wrap_content"        app:image="@{imageUrl}"/>    <TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="@{time}"/></layout>

java
binding.setImageUrl("https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/logo_white_fe6da1ec.png");
binding.setTime(new Date());

public class Utils {//BindingAdapter  参数是控件中使用的自定义属性名称(image)    @BindingAdapter({"bind:image"})    public static void imageLoader(ImageView imageView, String url) {        Glide.with(imageView.getContext()).load(url).into(imageView);    }    //数据的转换    @BindingConversion    public static String convertDate(Date date) {        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");        return sdf.format(date);    }}
原创粉丝点击