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: ");
}
}