您的位置:首页 > 移动开发 > Android开发

浅谈Android中MVC、MVP、MVVM模式(三)

2016-09-09 23:33 453 查看
三、MVVM的义军突起
    前面,在《浅谈Android中MVC、MVP、MVVM模式(一)》浅谈Android中MVC、MVP、MVVM模式(二)中我们学习了MVC和MVP,并分析了两者的差异,下面就让我们继续学习下MVVM。

    MVVM是Model-View-ViewModel的简写,MVVM框架的由来便是MVP模式与WPF结合的应用方式时发展演变过来的一种新型架构框架。

    MVVM包含了三部分:

Model : 业务逻辑和实体模型
View :显示内容
ViewModel : 将前面两者联系在一起的对象(实现ViewModle,谷歌官方提供了一个工具,DataBinding)
Android Data Binding前言,

    2015年的I/O大会上谷歌介绍了一个非常牛逼的工具,该工具可以让你将View和一个对象的field绑定。当field更新的时候,framework将收到通知,然后View自动更新。 Data Binding 官方原生支持MVVM模型可以让我们在不改变既有代码框架的前提下,非常容易的使用这些新特性。

谷歌官方文档 file:///.../sdk/docs/tools/data-binding/guide.html



MVVM 也是基于MVC上的一种演变, 它将Activity中的View给拆分出来了,再通过谷歌提供的DataBinding工具将View和Model关联到一起。

它可以用一个简单的模型图表示



与MVC、MVP对比来看, MVVM看起来似乎更为简洁,思路更明确了。从代码上来看,主要是依赖于DataBinding工具的强大支持

下面, 还是让我们用一个模拟登陆的简单Demo来演示一下,

先看项目结构



OK, 接下来一步一步的编写思路。

(一)Model

实体类User 和业务类UserLoginHttp, 更MVC中的一样, 不再贴出代码了。

此处贴出另一种实体User类的写法, 便于 将View和一个对象的field绑定,具体请参考Google的官方文档

//Model 实体
public class User {
public final ObservableField<String> username = new ObservableField<>();
public final ObservableField<String> password = new ObservableField<>();
}

(二)View

这里的View除了Layout布局之外, 还包括View的一些事件的处理, 我们想看Layout

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<!--如果想User与EditText关联起来,需要引入User-->
<data>

<variable
name="event"
type="com.ctao.demos.blogcodes.mvvm.event.UserEvent" />
</data>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="42dp">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="username: " />

<EditText
android:id="@+id/et_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:addTextChangedListener="@{event.usernameWatcher}" />
</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:orientation="horizontal">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="password: " />

<EditText
android:id="@+id/et_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:addTextChangedListener="@{event.passwordWatcher}" />
</LinearLayout>

<Button
android:id="@+id/bt_login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:text="login" />

</LinearLayout>
</layout>


可以发现, 我们这里的Layout布局和我们之前说些的有点不一样,在我们的根节点外又套了一层<layou>标签。在标签的里面的data标签中声明了一个event类,然后在EditText控件里关联了event里的事件,具体写法也请参看谷歌官方文档, 这里就不细说了。

接下来是处理View事件的UserEvent

//View (和Layout组合成View)
public class UserEvent {

private User user;

public UserEvent(User user){
this.user = user;
}

public TextWatcher usernameWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}

@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}

@Override
public void afterTextChanged(Editable editable) {
user.setUsername(editable.toString());
}
};

public TextWatcher passwordWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}

@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}

@Override
public void afterTextChanged(Editable editable) {
user.setPassword(editable.toString());
}
};
}


(三)ViewModel

    在写ViewModel也就是我们Activity之前, 我们先要配置下gredle,配置的要求,在上面第一张图已经说的很明确了。配置好之后,我们同步一下代码, 在我们的build子目录下会自动生成一个xxxBinding.java的类,如图



然后,我们就在Activity中依赖 ActivityMvvmloginBinding这个类,去实现Model和View的关联, 

//ViewModel 通过DataBinding将View和Model联系在一起
public class MvvmLoginAvtivity extends AppCompatActivity implements View.OnClickListener {

private ProgressDialog mPdLoading; // xml中没有, 不能分离
private User user;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

//setContentView
ActivityMvvmloginBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_mvvmlogin);

//绑定Event
user = new User();
UserEvent userEvent = new UserEvent(user);
binding.setEvent(userEvent);

mPdLoading = new ProgressDialog(this);
findViewById(R.id.bt_login).setOnClickListener(this);
}

@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.bt_login:
login();
break;
}
}

//登录
private void login() {
//业务处理
mPdLoading.show();
UserLoginHttp loginHttp = new UserLoginHttp(new Handler());
loginHttp.login(user.getUsername(), user.getPassword(), new UserLoginHttp.onResultListener<User>() {
@Override
public boolean onResult(int state, List<User> data, User result) {
mPdLoading.dismiss();
if (state == UserLoginHttp.STATE_SUCCEED) {
Toast.makeText(getApplication(), user.getUsername() +
" login success , to MainActivity", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplication(),
"login failed", Toast.LENGTH_SHORT).show();
}
return false;
}
});
}
}


OK, 到此MVVM的一个简单demo就算是完工了, 在实际项目中要使用MVVM着手搭建架构的话, 必须就得对DataBingding的使用异常了解。

总结,由于Android中的MVC模式使得我们的Activity既包含界面相关又包含业务相关,为了减少Activity的职责,衍生了两种解决思路

将Activity中的业务部分拆分出来,既出现了——MVP

将Activity中界面相关内容拆分出来,既出现了—— MVVM

以上是个人学习的一些整理,纯属个人见解,欢迎讨论和吐槽~

《源码下载》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: