集成官方的Data-Binding
可以直接参考 sample-databinding
官方的Data-Binding是一个避免了反射的MVVM的实现。不过说实话,个人觉得比较鸡肋。渲染逻辑在实际编写中,有大量的图片加载逻辑、自定义View逻辑等等,仍然无法完全用Xml的表达式来替代,而必须使用各类Attribute Setters, Converters。这意味着渲染逻辑会存在于两个以上位置,这将会对代码的可维护性造成极大的破坏,因为不同的程序员对一个渲染步骤是放在Java还是放在Xml中用表达式有着不同的理解。对于比Reactjs这种js框架,其渲染逻辑和样式Html是放在一处的,避免了这个问题。与此同时,Data-Binding也不能解决Activity的代码量过大的问题,只减少了部分代码,同时让一切变的更混乱了。
Anyway,如果你确定想使用Data-Binding,Pan也仍然支持,稍加改造即可。
首先,我们添加一个DataBindingViewModel,支持设置Data和其Binding:
public abstract class DataBindingViewModel<D extends BaseObservable, B extends ViewDataBinding> extends GeneralViewModel { protected D mData; protected B mViewDataBinding; public DataBindingViewModel<D, B> setData(D data){ mData = data; bindData(data); return this; } public D getData(){ return mData; } protected abstract void bindData(D data); @Override protected void onInit() { super.onInit(); mViewDataBinding = DataBindingUtil.bind(getRootView()); } }
在onInit的时候,自动找到Binding的对象,这样子类只需重写bindData这一步即可,同时,子类的render留空,例如:
public class MainDataBindingViewModel extends DataBindingViewModel<User, ActivityMainBinding> { @Override protected void bindData(User data) { mViewDataBinding.setUser(data); } @Override public MainDataBindingViewModel render() { return this; } }
User是一个实现了BaseObserverable的实体类,比较普通,下面是User类:
public class User extends BaseObservable { String name; @Bindable public String getName() { return name; } public void setName(String name) { this.name = name; notifyPropertyChanged(BR.name); } public User(){} public User(String name){ this.name = name; } }
搭配的界面Xml:
<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="cn.campusapp.sample_databinding.User"/> </data> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.name}"/> </RelativeLayout> </layout>
这样,搭配的Controller通过控制mUser对象的field,达到自动刷新界面的效果。如果想要实现DataBinding中的onclick,也比较简单,按照文档代理到Controller即可,可以直接看源码中的sample-databinding模块,就不再赘述。