mvp和mvvm框架笔记

理论

1.mvp

其中数据逻辑相当于M,Activity(负责View的绘制以及与用户交互)相当于V ,View于Model间的交互则为P,Model与View之间的交互由Presenter完成。还有一点就是Presenter与View之间的交互是通过接口的。
总结:

  1. 各部分之间的通信,都是双向的。
  2. View 与 Model 不发生联系,都通过 Presenter 传递。
  3. View 非常薄,不部署任何业务逻辑,称为”被动视图”(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。

2.mvvm

MVVM是Model-View-ViewModel的简写. 它是有三个部分组成:Model、View、ViewModel。Model:数据模型层。包含业务逻辑和校验逻辑,View:屏幕上显示的UI界面(layout、views),ViewModel:View和Model之间的链接桥梁,处理视图逻辑。
当View有用户输入后,ViewModel通知Model更新数据,同理Model数据更新后,ViewModel通知View更新。
总结:
MVVM 模式将 Presenter 改名为 ViewModel,基本上与 MVP 模式完全一致。唯一的区别是,它采用双向绑定(data-binding):View的变动,自动反映在 ViewModel,反之亦然。

mvp的使用

首先是M(数据逻辑)

UserModel.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class UserModel {
private String username;
private String password;
public UserModel(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int checkUserValidity(String username, String password) {
if (username == null || password == null ||
username.isEmpty() ||
password.isEmpty()) {
return -1;
}
return 0;
}
}

然后是V(View的绘制以及与用户交互)——通过interface(接口)与View(Activity交互)

接口
ILoginView.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public interface ILoginView {
void showProgress();
void hideProgress();
void setPasswordError();
String getUsername();
String getPassword();
void loginSuccess();
}

Activity
实现接口
LoginActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public class LoginActivity extends AppCompatActivity implements ILoginView,View.OnClickListener{
private EditText usernameEdit,passwrodEdit;
private Button loginButton;
ProgressDialog pd;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mvplogin);
pd = new ProgressDialog(this);
usernameEdit = (EditText) findViewById(R.id.et_username);
passwrodEdit = (EditText) findViewById(R.id.et_username);
loginButton = (Button) findViewById(R.id.bt_login);
loginButton.setOnClickListener(this);
}
@Override
public void showProgress() {
pd.show();
}
@Override
public void hideProgress() {
pd.cancel();
}
@Override
public void setPasswordError() {
passwrodEdit.setError("passwrod error");
}
@Override
public String getUsername() {
return usernameEdit.getText().toString();
}
@Override
public String getPassword() {
return passwrodEdit.getText().toString();
}
@Override
public void loginSuccess() {
Toast.makeText(this, "login success", Toast.LENGTH_SHORT).show();
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.bt_login:
break;
}
}

最后是P(View于Model间的交互)

与Model间交互接口
ILoginPresenter.java

1
2
3
4
5
public interface ILoginPresenter {
void Login(String username, String password);
}

实现接口
LoginPresenter.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class LoginPersenter implements ILoginPresenter{
private ILoginView loginView;
private UserModel mUser;
public LoginPersenter(ILoginView loginView) {
this.loginView = loginView;
initUser();
}
private void initUser(){
mUser = new UserModel(loginView.getUsername(),loginView.getPassword());
}
@Override
public void Login(String username, String password) {
loginView.showProgress();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
loginView.hideProgress();
int code = mUser.checkUserValidity(loginView.getUsername(), loginView.getPassword());
if (code == -1) {
loginView.setPasswordError();
} else if (code == 0) {
loginView.loginSuccess();
}
}
},2000);
}
}

最后在LoginActivity中补上P的调用

LoginActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
....
protected void onCreate(Bundle savedInstanceState) {
...
...
}
....
//初始化
loginPresenter = new LoginPersenter(this);//方便使用LoginActivity里的方法
...
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.bt_login:
//Click方法中的调用
loginPresenter.Login(usernameEdit.getText().toString(),passwrodEdit.getText().toString());
break;
}
.....

Done!

mvvm的使用

首先是M(数据逻辑)和mvp一样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class UserModel extends BaseObservable{
private String username;
private String password;
public UserModel(String username, String password) {
this.username = username;
this.password = password;
}
@Bindable
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
notifyPropertyChanged(BR.username);
}
@Bindable
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
notifyPropertyChanged(BR.password);
}
public int checkUserValidity() {
if (username == null || password == null ||
username.isEmpty() ||
password.isEmpty()) {
return -1;
}
return 0;
}
}

接下来是V(屏幕上显示的UI界面 layout、views)

这里涉及到databinding,先解释下databinding用法。

使用databinding

配置

在app的build.gradle上加上以下代码,配置之后,就可以开始使用数据绑定了。

1
2
3
4
5
6
7
8
android {
...
...
...
dataBinding{
enabled true
}
}

使用

要使用数据绑定,我们得首先创建一个实体类,例如使用上面的M(UserModel.java)

然后我们来看看布局文件该怎么写,首先布局文件不再是以传统的某一个容器作为根节点,而是使用作为根节点,在节点中我们可以通过节点来引入我们要使用的数据源。

在data中定义的variable节点,name属性表示变量的名称,type表示这个变量的类型,实例就是我们实体类的位置。
activity_mvvmlogin.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="user"
type="com.netease.mvpormvvmdemo.mvvm.UserModel"/>
</data>
<!--
也可以用import写法
<data>
<import type="com.netease.mvpormvvmdemo.mvvm.UserModel"/>
<variable
name="user"
type="UserModel"/>
</data>
-->
<LinearLayout
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/et_username"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/et_password"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/bt_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Login"
/>
</LinearLayout>
</layout>

最后是VM(View和Model之间的链接桥梁,处理视图逻辑。)

LoginActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class LoginActivity extends AppCompatActivity{
ActivityMvvmloginBinding binding;
ProgressDialog pd;
UserModel userModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//绑定
binding = DataBindingUtil.setContentView(this, R.layout.activity_mvvmlogin);
pd = new ProgressDialog(this);
binding.btLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
userModel = new UserModel(binding.etUsername.getText().toString(),binding.etPassword.getText().toString()); //使用绑定类的方法
binding.setUser(userModel);
doLoign();
}
});
}
private void doLoign(){
pd.show();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
pd.cancel();
int code = userModel.checkUserValidity();
if (code == -1) {
//使用绑定view
binding.etPassword.setError("passwrod error");
} else if (code == 0) {
Toast.makeText(getBaseContext(), "login success", Toast.LENGTH_SHORT).show();
}
}
},2000);
}
}

Done!
更详细的mvvm可以转去 http://blog.csdn.net/u012702547/article/details/52077515