android 开发选择,Android开发架构选择MVP or MVVM

写在前面的几句话

最近有打算写一些独立的App的打算,所以对现在的Android架构与技术的选择进行了重新的思考,抛开那些乱七八糟的东西,以一个极客的态度去选择。

首先我们来看看Android开发中的几大架构

一.MVC,MVP,MVVM的区分

1.MVC

传统的Android App其实都是基于MVC的,Activity,Fragment相当于C,布局相当于V,数据逻辑相当于M

随着业务的增长Controller里的代码会越来越臃肿,因为它不只要负责业务逻辑,还要控制View的展示。也就是说Activity、Fragment杂糅了Controller和View,耦合变大。并不能算作真正意义上的MVC。

这也是为什么后面的MVP会引起很多开发者兴趣的原因了。

2.MVP

MVP架构其实可以说与MVC的架构还是有很大的差别的,数据逻辑相当于M,Activity(负责View的绘制以及与用户交互)相当于V ,View于Model间的交互则为P

理论上感觉区别有点抽象,可以通过下面的图来看一看其中的区别

2fbb3fc84449

图1 MVC与MVP的区别

其实最明显的区别就是,MVC中是允许Model和View进行交互的,而MVP中很明显,Model与View之间的交互由Presenter完成。还有一点就是Presenter与View之间的交互是通过接口的

3.MVVM

MVVM是Model-View-ViewModel的简写. 它是有三个部分组成:Model、View、ViewModel。Model:数据模型层。包含业务逻辑和校验逻辑,View:屏幕上显示的UI界面(layout、views),ViewModel:View和Model之间的链接桥梁,处理视图逻辑。

当View有用户输入后,ViewModel通知Model更新数据,同理Model数据更新后,ViewModel通知View更新。

MVVM其实与MVP架构看起来很相似

2fbb3fc84449

图2 MVP与MVVM

这里可以可以看到 ViewModel 承担了 Presenter 中与 view和 Model 交互的职责,与 MVP模式不同的是,VM与 V 之间是通过 Datebinding 实现的,而 P是持有 View 的对象,直接调用 View 中的一些接口方法来实现。ViewModel可以理解成是View的数据模型和Presenter的合体。它通过双向绑定(松耦合)解决了MVP中Presenter与View联系比较紧密的问题,然而Android中的Datebinding只能单向绑定,只能从ViewModel绑定到View中

二 .MVP and MVVM代码对比

接下来就对同一功能用MVP与MVVM架构来实现,通过代码对比,分析到底选择哪一种比较好

代码很简单就用登录的简单逻辑

2fbb3fc84449

图1 demo截图

Mvp代码实现

首先看下结构

数据逻辑相当于M

Activity(负责View的绘制以及与用户交互)相当于V

View与Model间的交互则为P

2fbb3fc84449

图2 Mvp代码结构

从M开始

UserModel.Class

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

ILoginView.Class

public interface ILoginView {

void showProgress();

void hideProgress();

void setPasswordError();

String getUsername();

String getPassword();

void loginSuccess();

}

LoginActivity.Class

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了

ILoginPresenter.Class

public interface ILoginPresenter {

void Login(String username, String password);

}

LoginPresenter.Class

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的调用

//初始化

loginPresenter = new LoginPersenter(this);

//Click方法中的调用

loginPresenter.Login(usernameEdit.getText().toString(),passwrodEdit.getText().toString());

到这里MVP模式的代码就已经实现了

Mvvm代码实现

Model:数据模型层。包含业务逻辑和校验逻辑

View:屏幕上显示的UI界面(layout、views)

ViewModel:View和Model之间的链接桥梁,处理视图逻辑。

2fbb3fc84449

图3 Mvvm代码结构

从M开始

UserModel.Class

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

activity_mvvmlogin.xml

name="user"

type="com.netease.mvpormvvmdemo.mvvm.UserModel"/>

android:orientation="vertical" android:layout_width="match_parent"

android:layout_height="match_parent">

android:id="@+id/et_username"

android:layout_width="match_parent"

android:layout_height="wrap_content" />

android:id="@+id/et_password"

android:layout_width="match_parent"

android:layout_height="wrap_content" />

android:id="@+id/bt_login"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="Login"

/>

最后是VM了

LoginActivity.Class

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) {

binding.etPassword.setError("passwrod error");

} else if (code == 0) {

Toast.makeText(getBaseContext(), "login success", Toast.LENGTH_SHORT).show();

}

}

},2000);

}

}

到这里MVVM的代码也实现了

是不是看到这里觉得这不是很坑爹嘛?MVVM的写法和以前MVC的写法基本一样呀?这样还有什么意义?

确实一样,这是为什么呢?其实之前介绍的时候也有提到过Android中的Datebingding只能单向绑定,只能从ViewModel绑定到View中,所以呢View中数据的变化我们在ViewModel中并不能拿到,所以写法和MVC没有什么区别

但是我们可以从ViewModel绑定到View中,这里其实就有很大的变化了

那我们修改一下登陆逻辑,登录后清除界面元素信息,显示成功页或者失败页

MVP架构的代码就不书写了,和之前的是一样结构的,主要是来看下MVVM从ViewModel绑定到View中

首先修改下Model

public class UserModel extends BaseObservable{

private String username;

private String password;

private int status = 1;

@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);

}

@Bindable

public int getStatus() {

return status;

}

public void setStatus(int status) {

this.status = status;

notifyPropertyChanged(BR.status);

}

public void checkUserValidity() {

if (username == null || password == null ||

username.isEmpty() ||

password.isEmpty()) {

setStatus(-1);

}else {

setStatus(0);

}

}

}

这里主要是增加了一个新的属性为status,这个属性主要是用作判断当前界面的状态

接下来看看view的修改

name="user"

type="com.netease.mvpormvvmdemo.mvvm.UserModel"/>

android:layout_width="match_parent"

android:layout_height="match_parent"

>

android:orientation="vertical"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:visibility="@{user.status == 1 ? View.VISIBLE : View.GONE}"

>

android:id="@+id/et_username"

android:layout_width="match_parent"

android:layout_height="wrap_content" />

android:id="@+id/et_password"

android:layout_width="match_parent"

android:layout_height="wrap_content" />

android:id="@+id/bt_login"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="Login"

/>

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

android:visibility="@{user.status == 0 ? View.VISIBLE : View.GONE}"

>

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@{user.username}"

/>

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@{user.password}"

/>

android:layout_width="match_parent"

android:layout_height="match_parent"

android:visibility="@{user.status == -1 ? View.VISIBLE : View.GONE}"

>

android:layout_width="match_parent"

android:layout_height="match_parent"

android:gravity="center"

android:text="error"

/>

view内主要是修改为三个布局,根据status的状态进行变化

最后看看viewmodel的变化,viewmodel其实没有怎么变化,因为model里面小的修改了下

private void doLoign(){

pd.show();

new Handler().postDelayed(new Runnable() {

@Override

public void run() {

pd.cancel();

userModel.checkUserValidity();

}

},2000);

}

这里的代码只有这些

当我们输入后点击login后,model会对输入状态取检测,从而改变model里面的status属性,而通过ViewModel,view会及时拿到最新的状态,从而通过判断去做view层的变化。这就是MVVM的绑定机制了

看下运行截图

2fbb3fc84449

图4 Mvvm

三.对比结论与分析

通过代码的对比,明显可以发现Mvp模式下的代码量相对来说确实增加了很多,但是逻辑相对的更加清晰,所以我觉得Mvp模式不是很适合小型的项目,小型项目整一堆类出来确实不是很好的事情,但是如果是一个较大型的项目还是可以选用这种架构来做开发,毕竟逻辑清晰,维护起来也比较方便。

而Mvvm的架构我个人觉得是Android往后发展的趋势,毕竟谷歌都推出了Datebinding,而使用Datebinding也就可以不用去使用bufferknife了,而且绑定的这种机制也确实带来了model,view与vm的分离,从逻辑上看也确实清晰了很多,问题是暂时只支持单向绑定,这个也要等谷歌后面的更新了,而且代码的阅读性会下降很多,所以呢这个比较时候小型的极客项目,暂时不适合大型的项目。

写在后面的几句话

其实架构性的东西在我看来没有一定的固定的写法,包括mvp和mvvm也可以根据自己的业务和理解去做不同的代码区分,像前阵子也有人提出了基于MVP与MVVM的mvvmp的架构,所有架构是死的,人是活的,记得面试听过一个大神说要跳出设计模式的圈圈,会有很多新的发现。。。共勉

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android开发中,MVPMVVM是两种常用的架构模式。 MVP(Model-View-Presenter)模式中,View负责展示数据和处理用户交互,Model负责数据的获取和处理,Presenter作为中间人连接View和Model,负责处理业务逻辑。MVP模式通过Presenter来解决View和Model的直接通信,提高了代码的复用性、可拓展性和降低了耦合度。但是,MVP模式会增加很多接口和实现类,代码量相对较大,适用于中小型项目,不太适合大型项目。\[2\] MVVM(Model-View-ViewModel)模式是在MVP的基础上进一步发展和规范的。MVVM模式中,ViewModel负责处理业务逻辑和数据的获取,View负责展示数据和处理用户交互,Model负责数据的存储和处理。MVVM模式引入了Data Binding的概念,通过Binding来实现View接口的实现方法,使代码更加优雅简洁。MVVM模式相对于MVP模式更加灵活和方便测试。\[3\] 所以,MVPMVVM都是为了解决MVC模式中代码臃肿、耦合度高等问题而提出的。MVP通过Presenter来解决View和Model的直接通信,而MVVM通过Data Binding来实现View接口的实现方法,使代码更加优雅简洁。在Android开发中,根据项目的规模和需求选择适合的架构模式是很重要的。 #### 引用[.reference_title] - *1* [一篇文章讲清楚Android中的MVC、MVPMVVM架构 (附实现代码)](https://blog.csdn.net/bugyinyin/article/details/128932821)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Android的三种开发模式 mvc mvp mvvm](https://blog.csdn.net/qq_43649223/article/details/120746596)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值