MVC简介
MVC全名是Model View Controller,如图,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。
其中M层处理数据,业务逻辑等;V层处理界面的显示结果;C层起到桥梁的作用,来控制V层和M层通信以此来达到分离视图显示和业务逻辑层。
缺点:
Activity既是controller层,又是view层,导致Activity臃肿,不好维护
场景分析:
1.大家想过这样会有什么问题吗?显然是有的,不然为什么会有MVP和MVVM的诞生呢,是吧。问题就在于xml作为view层,控制能力实在太弱了,你想去动态的改变一个页面的背景,或者动态的隐藏/显示一个按钮,这些都没办法在xml中做,只能把代码写在activity中,造成了activity既是controller层,又是view层的这样一个窘境。大家回想一下自己写的代码,如果是一个逻辑很复杂的页面,activity或者fragment是不是动辄上千行呢?这样不仅写起来麻烦,维护起来更是噩梦。
2.以前用volley,现在切换成Afinal框架实现网络请求,你怎么解决问题?MVC不好搞定,一般修改不仅破坏了以前的代码,而且还不利于维护, 考虑到以后代码的扩展和维护性,我们选择设计接口的方式来解决着一个问题就是MVP
代码示例:就是我们常常写的,这里不贴了
什么是MVP?
从图中就可以看出,最明显的差别就是view层和model层不再相互可知从图中就可以看出,最明显的差别就是view层和model层不再相互可知,完全的解耦,取而代之的presenter层充当了桥梁的作用
MVP则是使用P截断了M与V之间的联系,降低了复杂程度,指责结构简单明了;
因此,Activity及从MVC中的Controller中解放出来了,这会Activity主要做显示View的作用和用户交互。每个Activity可以根据自己显示View的不同实现View视图接口IUserView。
MVP模式的优点:
- 在MVP中,Activity的代码不臃肿;
- 在MVP中,Model(IUserModel的实现类)的改动不会影响Activity(View),两者也互不干涉,而在MVC中会;
- 在MVP中,IUserView这个接口可以实现方便地对Presenter的测试;
- 在MVP中,UserPresenter可以用于多个视图,但是在MVC中的Activity就不行。
- 明显可以发现Mvp模式下的代码量相对来说确实增加了很多,但是逻辑相对的更加清晰,所以我觉得Mvp模式 不是很适合小型的项目,小型项目整一堆类出来确实不是很好的事情,但是如果是一个较大型的项目还是可以选 用这种架构来做开发,毕竟逻辑清晰,维护起来也比较方便。
-
MVP缺点:
MVP的问题在于,由于我们使用了接口的方式去连接view层和presenter层,这样就导致了一个问题,如果你有一个逻辑很复杂的页面,你的接口会有很多,十几二十个都不足为奇。想象一个app中有很多个这样复杂的页面,维护接口的成本就会非常的大。
-
private EditText usernameEdit,passwrodEdit; private Button loginButton; ProgressDialog pd; /*** * 采用MVP编程 * @param savedInstanceState */ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); pd = new ProgressDialog(this); usernameEdit = (EditText) findViewById(R.id.et_username); passwrodEdit = (EditText) findViewById(R.id.et_password); loginButton = (Button) findViewById(R.id.bt_login); loginButton.setOnClickListener(this); //初始化 loginPresenter = new LoginPersenter(this); } LoginPersenter loginPresenter; @Override public void onClick(View v) { loginPresenter.Login(usernameEdit.getText().toString(),passwrodEdit.getText().toString()); } @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(); }
-
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); }
public interface ILoginPresenter { void Login(String username, String password); }
public interface ILoginView { void showProgress(); void hideProgress(); void setPasswordError(); String getUsername(); String getPassword(); void loginSuccess(); }
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; }
-
总结:多了接口,和Presenter的model和view封装
-
MVVM
MVVM是Model-View-ViewModel的简写。
了解MVVM+data binding的开发模式。
至于MVVM基本上和MVP一模一样,感觉只是名字替换了一下。他的关键技术就是今天的主题(Data Binding)。View的变化可以自动的反应在ViewModel,ViewModel的数据变化也会自动反应到View上。这样开发者就不用处理接收事件和View更新的工作,框架已经帮你做好了。
最近很火最主要的原因就是谷歌推出了data binding这个框架,可以轻松的实现MVVM。我个人觉得是Android往后发展的趋势,毕竟谷歌都推出了Datebinding,而使用Datebinding也就可以不用去使用bufferknife了
Data Binding的开发者贴心得为我们准备了一系列的ObservableField,包括: ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat,ObservableDouble, 以及 ObservableParcelable
原理和流程
环境要求 Data Binding对使用的环境还是有一定要求的(这货有点挑) Android Studio版本在1.3以上 gradle的版本要在1.5.0-alpha1以上
- ####创建对象 创建一个User类
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;
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/container"
android:orientation="vertical"
android:fitsSystemWindows="true">
<data>
<import type="com.example.gavin.databindingtest.User"/>
<variable
name="user"
type="User" />
</data>
<EditText
android:id="@+id/et_username"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
xml中的代码需要导入包
vm用到xml中的,需要声明
public class ImageUtil { /** * 使用ImageLoader显示图片 * @param imageView * @param url */ @BindingAdapter({"image"}) public static void imageLoader(ImageView imageView, String url) { ImageLoader.getInstance().displayImage(url, imageView); } /** * 使用ImageLoader显示图片 * @param view * @param b */ @BindingAdapter({"isVisibleOrGone"}) public static void isVisibleOrGone(View view, boolean b) { int visiable; if (b) { visiable = View.VISIBLE; } else { visiable = View.GONE; } view.setVisibility(visiable); }
public class ImageUtil { /** * 使用ImageLoader显示图片 * @param imageView * @param url */ @BindingAdapter({"bind:image"}) public static void imageLoader(ImageView imageView, String url) { ImageLoader.getInstance().displayImage(url, imageView);
public class User extends BaseObservable {
private String firstName;
private String lastName;
public boolean isStudent = true;
public User(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
@Bindable
public String getFirstName() {
return this.firstName;
}
@Bindable
public String getLastName() {
return this.lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
notifyPropertyChanged(BR.lastName);
}
public void setFirstName(String firstName) {
this.firstName = firstName;
notifyPropertyChanged(BR.firstName);
}
}
public static String mName = "MM";
private ActivityMainBinding binding;
private User user;
private User2 mUser2;
List<User2> data = new ArrayList<>();
MyAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
user = new User("Micheal", "Jack");
binding.setUser(user);
binding.setHandle(new MyHandler());
mUser2 = new User2();
mUser2.firstName.set("Mr");
mUser2.lastName.set("Bean");
mUser2.age.set(5);
mUser2.isStudent.set(false);
binding.setUser2(mUser2);
ImageLoaderConfiguration configuration = ImageLoaderConfiguration.createDefault(this);
ImageLoader.getInstance().init(configuration);
binding.setImageUrl("http://115.159.198.162:3000/posts/57355a92d9ca741017a28375/1467250338739.jpg");
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:image = "@{imageUrl}"/>
DataBindingUtil和
BaseObservable是databing自带的
看到View和VM紧紧的联系在了一起
大总结:
- MVC:(VIew-Model-Controller) 早期将VIew、Model、Controller代码块进行划分,使得程序大部分分离,降低耦合。
- MVP:(VIew-Model-Presenter)由于MVC中View和Model之间的依赖太强,导致Activity中的代码过于臃肿。为了他们可以绝对独立的存在,慢慢演化出了MVP。在MVP中View并不直接使用Model,它们之间的通信是通过 Presenter (MVC中的Controller)来进行的。
- MVVM:必须先学会DataBinding(Model–View–ViewModel) MVVM可以算是MVP的升级版,将 Presenter 改名为 ViewModel。关键在于View和Model的双向绑定,当View有用户输入后,ViewModel通知Model更新数据,同理Model数据更新后,ViewModel通知View更新。
ASdemo的下载地址:点击打开链接