DataBinding实现MVVM

来源:互联网 发布:出纳票据打印软件 编辑:程序博客网 时间:2024/05/16 14:15

这里写图片描述
ViewModel和Model双向绑定,ViewModel和View单向绑定

Observable

任何 POJO 对象都能用在 Data Binding 中,但是更改 POJO 并不会同步更新 UI。Data Binding 的强大之处就在于它可以让你的数据拥有更新通知的能力。

有三种不同的动态更新数据的机制:

Observable 对象
Observable 字段
Observable 容器类
当以上的 observable 对象绑定在 UI 上,数据发生变化时,UI 就会同步更新。

Observable 对象

当一个类实现了 Observable 接口时,Data Binding 会设置一个 listener 在绑定的对象上,以便监听对象字段的变动。

Observable 接口有一个添加/移除 listener 的机制,但通知取决于开发者。为了简化开发,Android 原生提供了一个基类 BaseObservable 来实现 listener 注册机制。这个类也实现了字段变动的通知,只需要在 getter 上使用 Bindable 注解,并在 setter 中通知更新即可。

public class ObservableContact extends BaseObservable {    private String mName;    private String mPhone;    public ObservableContact(String name, String phone) {        mName = name;        mPhone = phone;    }    @Bindable    public String getName() {        return mName;    }    public void setName(String name) {        mName = name;        notifyPropertyChanged(BR.name);    }    @Bindable    public String getPhone() {        return mPhone;    }    public void setPhone(String phone) {        mPhone = phone;        notifyPropertyChanged(BR.phone);    }}

BR 是编译阶段生成的一个类,功能与 R.java 类似,用 @Bindable 标记过 getter 方法会在 BR 中生成一个 entry。
当数据发生变化时需要调用 notifyPropertyChanged(BR.firstName) 通知系统 BR.firstName 这个 entry 的数据已经发生变化以更新UI。
Observable和一般JavaBean在setData()时的区别
多了updateRegistration()

//User是Observablepublic void setUser(com.example.fs.databinding.model.User user) {        updateRegistration(0, user);        this.mUser = user;        synchronized(this) {            mDirtyFlags |= 0x1L;        }        notifyPropertyChanged(BR.user);        super.requestRebind();    }public void setHandler(ClickHandler handler) {        this.mHandler = handler;        synchronized(this) {            mDirtyFlags |= 0x2L;        }        notifyPropertyChanged(BR.handler);        super.requestRebind();    }

updateRegistration()创建弱引用了DataBinding的Listener,以lacalFieldId作为key存储起来。绑定Listener到Observable,也就是绑定DataBinding到Obervable。由于Listener注册并实现一个Callback,当Observable数据发生变化notifyPropertyChanged()时,可以通知Callback实现对View的更新,最终调用onFieldChange(int localFieldId, Object object, int fieldId)。
fieldId:用 @Bindable 标记过 getter 方法的数据,在BR中会生成一个entry,

ObservableField

创建ObservableField类型public数据对象,ObservableFields 是继承自Observable 对象的单一字段。

public class ObservableFieldContact {    public ObservableField<String> mName = new ObservableField<>();    public ObservableFieldContact(String name) {        mName.set(name);    }}

使用数据时

mObservableFieldContact.mName.set("ConnorLin");String name = mObservableFieldContact.mName.get();

和继承Observable的区别是在executeBindings()里注册ObservableField的监听

@Overrideprotected void executeBindings() {    long dirtyFlags = 0;    synchronized(this) {        dirtyFlags = mDirtyFlags;        mDirtyFlags = 0;    }    ...    if ((dirtyFlags & 0xfL) != 0) {        if ((dirtyFlags & 0xdL) != 0) {            if (contact != null) {                // read contact.mName                mNameContact = contact.mName;            }            updateRegistration(0, mNameContact);       ...    }    ...}

Observable 容器类

ObservableArrayMap<String, Object> user = new ObservableArrayMap<>();user.put("firstName", "Google");user.put("lastName", "Inc.");user.put("age", 17);

layout中使用

<data>    <import type="android.databinding.ObservableMap"/>    <variable name="user" type="ObservableMap&lt;String, Object&gt;"/></data>…<TextView   android:text='@{user["lastName"]}'   android:layout_width="wrap_content"   android:layout_height="wrap_content"/><TextView   android:text='@{String.valueOf(1 + (Integer)user["age"])}'   android:layout_width="wrap_content"   android:layout_height="wrap_content"/>

事件绑定(View->Model)

Binding构造方法中会为View创建监听,每个监听有对应的控件序号

public ActivityObservableBinding(android.databinding.DataBindingComponent bindingComponent, View root) {        super(bindingComponent, root, 2);...        // listeners,2、1和下面的sourceId对应        mCallback2 = new android.databinding.generated.callback.OnClickListener(this, 2);        mCallback1 = new android.databinding.generated.callback.OnClickListener(this, 1);        invalidateAll();    }   

executeBindings时设置监听,当事件回调时,根据控件序号执行Handler对应的onClick()方法

public final void _internalCallbackOnClick(int sourceId , android.view.View callbackArg_0) {        switch(sourceId) {            case 2: {               ...                    handler.onClick(callbackArg_0);                ...                break;            }            case 1: {                // localize variables for thread safety                ...                    handler.onClick();                ...                break;            }        }    }
0 0
原创粉丝点击