MVVM
- MVVM是什么?
- MVVM实现
- 前提
- Model
- ViewModel
- View
 
MVVM是什么?
Model-View-ViewMode架构,可看作MVP改进版,将此前Presenter的逻辑操作交给ViewMode中的Binder去处理

- Mode:封装数据存储及相关操作逻辑,与MVC/MVP不同的是会提供一系列实体类与UI绑定,ViewModel修改这些数据后将数据变化告诉View
- View:处理界面逻辑但不参与业务逻辑,显示ViewModel提供的数据
- ViewModel:视图模型与视图状态的合称,为View提供一个可供显示的数据模型并收集、处理这些数据,内部的Binder用于双向绑定,还可包含多个Child ViewModel
MVVM实现
前提
在build.gradle中android节点添加如下代码(最低SDK版本为API7,Gradle版本为1.5.0-alpha1)
dataBinding{
    enabled = true
}
Model
创建数据实体类LoginInfo
- 继承BaseObservable
- getXXX()方法通过@Bindable注解表示该方法所返回的数据被修改时会更新UI
- setXXX()方法调用notifyPropertyChanged()告诉DataBinding该字段被更改
public class LoginInfo extends BaseObservable {
    private String mUser;
    private String mPassword;
    public LoginInfo(String user, String password) {
        mUser = user;
        mPassword = password;
    }
    @Bindable
    public String getUser() {
        return mUser;
    }
    public void setUser(String user) {
        mUser = user;
        notifyPropertyChanged(BR.user);
    }
    @Bindable
    public String getPassword() {
        return mPassword;
    }
    public void setPassword(String password) {
        mPassword = password;
        notifyPropertyChanged(BR.password);
    }
}
ViewModel
LoginModel封装维护LoginInfo、点击事件、文本改变事件
public class LoginModel {
    private static final String DEF_USER = "song";
    private static final String DEF_PASSWORD = "123";
    public LoginInfo mInfo;
    private OnLoginListener mListener;
    public LoginModel(OnLoginListener listener) {
        mListener = listener;
        mInfo = new LoginInfo("", "");
    }
    public TextWatcher getUserTextWatcher() {
        return new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }
            @Override
            public void afterTextChanged(Editable s) {
                mInfo.setUser(s.toString());
            }
        };
    }
    public TextWatcher getPasswordTextWatcher() {
        return new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }
            @Override
            public void afterTextChanged(Editable s) {
                mInfo.setPassword(s.toString());
            }
        };
    }
    public interface OnLoginListener {
        void onLoginSuccess();
        void onLoginFail();
    }
    public void onLoginClick(View view) {
        if (mInfo.getUser().equals(DEF_USER) && mInfo.getPassword().equals(DEF_PASSWORD)) {
            mListener.onLoginSuccess();
        } else {
            mListener.onLoginFail();
        }
    }
}
View
xml文件根节点变为layout,布局分为
- 数据部分:声明所使用到的数据实体类以及构造该对象时的引用名
- UI部分:常规控件,可直接使用数据实体类对象中的字段、方法
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="model"
            type="com.demo.demo0.LoginModel" />
    </data>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_horizontal"
        android:orientation="vertical">
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:addTextChangedListener="@{model.getUserTextWatcher}"
            android:hint="User"
            android:text="@{model.mInfo.getUser}" />
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:addTextChangedListener="@{model.getPasswordTextWatcher}"
            android:hint="Password"
            android:text="@{model.mInfo.getPassword}" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{model.onLoginClick}"
            android:text="Login" />
    </LinearLayout>
</layout>
MainActivity开启线程3秒后修改数据会显示在UI
- 通过DataBindingUtil.setContentView设置布局,布局名字为R.layout.ab_cd,则对应类为AbCdBinding,为其设置Model
public class MainActivity extends AppCompatActivity implements LoginModel.OnLoginListener {
    private static final String TAG = "MainActivity";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        LoginModel model = new LoginModel(this);
        binding.setModel(model);
        new Thread(new Runnable() {
            @Override
            public void run() {
                SystemClock.sleep(3000);
                model.mInfo.setUser("New User");
                model.mInfo.setPassword("New Password");
            }
        }).start();
    }
    
    @Override
    public void onLoginSuccess() {
        Log.d(TAG, "onLoginSuccess: ");
    }
    
    @Override
    public void onLoginFail() {
        Log.d(TAG, "onLoginFail: ");
    }
}



















