美文网首页
Android 之浅谈:MVC、MVP

Android 之浅谈:MVC、MVP

作者: 是takiku啊 | 来源:发表于2019-12-04 16:40 被阅读0次

在当下Android开发中一个合适的架构设计尤为重要,一个好的设计不仅可以减少我们的bug率,而且代码实现也更加的优雅。我们常见架构设计有MVC、MVP、MVVM,这三种都有各自的优缺点。所有我们需根据实际业务的需求来选择合适的架构。那么了解这些设计模式的特点是非常有必要的,下文将浅谈这些架构特点。还有如果当我们项目到达一定的规模后,对项目进行组件化、插件化也是有一定的必要性的,它可以减少项目的臃肿,对项目进行分层分模块架构,让项目更具有可扩展性。

1、MVC

MVC是(Model-View-Controller, 模型-视图-控制器)的缩写,是软件设计中的一种典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,往往在Android里Activity即充当了部分视图层又充当了控制层,大量的代码会写在Activity里,xml布局相当于视图层,model则只负责与数据交换例如网络请求、本地数据库、文件读写等,当activity业务量并不复杂的情况下,具有简单明了的效果,但是一旦业务量或者逻辑众多会导致activity过于臃肿。

MVC代码例子

  • Model层

public class LoginModel {

public UserInfoEntitylogin(String userName,String pwd){  //模拟网络请求
        UserInfoEntity userInfoEntity=new UserInfoEntity();
        userInfoEntity.setUserName("是takiku啊");
        userInfoEntity.setAge(23);
        userInfoEntity.setSex(1);
        return  userInfoEntity;
    }
}

  • View层
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/ll_userinfo"
        android:visibility="gone"
       android:layout_above="@+id/ll_login"
        android:layout_marginBottom="100dp"
        android:layout_centerHorizontal="true"
        android:orientation="vertical">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/tv_username"
            android:text="用户名:hhhh"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="年龄:23岁"
            android:id="@+id/tv_age"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:id="@+id/tv_sex"
            android:text="性别:男"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/ll_login"
        android:orientation="vertical"
        android:layout_centerInParent="true">
        <EditText
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            android:id="@+id/et_account"
            android:hint="账号"
            android:layout_marginLeft="40dp"
            android:layout_marginRight="40dp"/>
        <EditText
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            android:hint="请输入密码"
            android:id="@+id/et_pwd"
            android:inputType="textPassword"
            android:layout_marginLeft="40dp"
            android:layout_marginRight="40dp"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/btn_login"
            android:layout_marginTop="20dp"
            android:layout_gravity="center_horizontal"
            android:text="登录"/>
    </LinearLayout>

</RelativeLayout>
  • Controller层
    private void toLogin() {
        if (check()){
            UserInfoEntity userInfoEntity= loginModel.login(accountTv.getText().toString(),pwdTv.getText().toString());
            if (userInfoEntity!=null){
                showUi(userInfoEntity);
            }
        }
    }

    private void showUi(UserInfoEntity userInfoEntity) {
        userInfoll.setVisibility(View.VISIBLE);
        userNameTv.setText(userInfoEntity.getUserName());
        ageTv.setText(userInfoEntity.getAge()+"岁");
        if (userInfoEntity.getSex()==0){
            sexTv.setText("性别:女");
        }else {
            sexTv.setText("性别:男");
        }
    }

2、MVP

使用MVC模式时当app业务越来越多的时,Activity或者Fragment里的代码就显得很臃肿了,大量的代码堆积在一个activity里,View层和Controller层就有一定的耦合,当业务调整时,修改起来会让人挺头疼的,而且由于更新操作是没有对activity周期进行绑定的也有可能出现空指针异常,例如当网络状态不佳的时候,用户打开一个页面非常慢此时用户点击返回,这时恰好网络请求回调好了进行UI更新, 但是此界面已经被销毁了,就很容易造成空指针异常。而MVP模式恰好解决了这一个痛点,M还是原来的M层 ,V变成了Activity或者fragment, View层只进行单一的UI操作,所有的逻辑操作放在P层,Presenter层是View和Model的桥梁,
MVP的核心思想:

MVP把Activity中的UI逻辑抽象成View接口,把业务逻辑抽象成Presenter接口,Model类还是原来的Model。

MVP代码例子

  • MVP模式的基类封装
    • 视图的基类
/**
 *     视图基类 可以发一些业务相关的公共视图显示
 */
public interface IBaseView {

}
  • MVPActivity基类
/**
 * author:chengwl
 * Description:     MVP的Activity基类

 * Date:2019/6/5
 */
public abstract class BaseMvpActivity<P extends IPresenter> extends BaseActivity implements IBaseView {

    protected P mPresenter;

    protected abstract P createPresenter();

    /**
     * p 层最先要做的事情
     */
    protected abstract void  initPresenter();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mPresenter = createPresenter();
        if (mPresenter == null) {
            throw new NullPointerException("Presenter is null! Do you return null in createPresenter()?");
        }
        mPresenter.onMvpAttachView(this, savedInstanceState);
        mPresenter.onMvpAttachContext(this);
        initPresenter();
    }
    @Override
    protected void onStart() {
        super.onStart();
        if (mPresenter != null) {
            mPresenter.onMvpStart();
        }
    }
    @Override
    protected void onResume() {
        super.onResume();
        if (mPresenter != null) {
            mPresenter.onMvpResume();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mPresenter != null) {
            mPresenter.onMvpPause();
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (mPresenter != null) {
            mPresenter.onMvpStop();
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        if (mPresenter != null) {
            mPresenter.onMvpSaveInstanceState(outState);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mPresenter != null) {
            mPresenter.onMvpDetachView(false);
            mPresenter.onMvpDestroy();
        }
    }
}
  • Presenter基本接口
/**
 * author:chengwl
 * Description:           P层接口:定义P层生命周期与 V层同步
 * Date:2019/6/5
 */
public interface IPresenter<V extends IBaseView> {
    void onMvpAttachView(V view, Bundle savedInstanceState);   //绑定View层

    void onMvpSaveInstanceState(Bundle savedInstanceState);

    void onMvpDetachView(boolean retainInstance);   //   解绑View层              需要的时候进行绑定,不需要的时候进行解绑就可以了

    void onMvpStart();

    void onMvpResume();

    void onMvpPause();

    void onMvpStop();

    void onMvpDestroy();

    void onMvpAttachContext(Context context);
}
  • Presenter基类
/**
 *      P层基类:
 *      Presenter生命周期包装、View的绑定和解除,P层实现的基类
 */
public abstract class BasePresenter<V extends IBaseView> implements IPresenter<V> {

    //View接口类型的软引用
    protected Reference<V> mViewRef;
    protected Reference<Context> mContextRef;


    public void attachView(V view){
        mViewRef=new SoftReference<V>(view);
    }
    protected V getView(){
        return mViewRef.get();
    }
    public boolean isViewAttached(){
        return mViewRef!=null&&mViewRef.get()!=null;
    }
    public void detachView(){
        if (mViewRef!=null){
            mViewRef.clear();
            mViewRef=null;
        }
        if (mContextRef!=null){
            mContextRef.clear();
            mContextRef=null;
        }

    }
    @Override
    public void onMvpAttachView(V view, Bundle savedInstanceState) {
      attachView(view);
    }
    @Override
    public void onMvpStart() {

    }

    @Override
    public void onMvpDetachView(boolean retainInstance) {
        detachView();
    }

    @Override
    public void onMvpResume() {

    }

    @Override
    public void onMvpPause() {

    }

    @Override
    public void onMvpStop() {

    }

    @Override
    public void onMvpAttachContext(Context context) {
        mContextRef=new SoftReference<>(context);
    }
}
  • Model层

public class LoginModel {

public UserInfoEntitylogin(String userName,String pwd){  //模拟网络请求
        UserInfoEntity userInfoEntity=new UserInfoEntity();
        userInfoEntity.setUserName("是takiku啊");
        userInfoEntity.setAge(23);
        userInfoEntity.setSex(1);
        return  userInfoEntity;
    }
}

  • View层
public class LoginMVPActivity extends BaseMvpActivity<LoginPresenter> implements ILoginView{
    private EditText accountTv;
    private EditText pwdTv;
    private TextView userNameTv;
    private TextView ageTv;
    private TextView sexTv;
    private Button loginBtn;
    private LoginModel loginModel;
    private LinearLayout userInfoll;
    @Override
    protected LoginPresenter createPresenter() {
        return new LoginPresenter();
    }

    @Override
    protected void initPresenter() {

    }
    @Override
    protected void initView() {
     
        accountTv=findViewById(R.id.et_account);
        pwdTv=findViewById(R.id.et_pwd);
        userInfoll=findViewById(R.id.ll_userinfo);
        loginBtn=findViewById(R.id.btn_login);
        userNameTv=findViewById(R.id.tv_username);
        ageTv=findViewById(R.id.tv_age);
        sexTv=findViewById(R.id.tv_sex);
        loginBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                toLogin();
            }
        });
    }
    private void toLogin() {
        mPresenter.login(accountTv.getText().toString(),pwdTv.getText().toString());
    }

    @Override
    public void onDataSuccess(UserInfoEntity userInfoEntity) {
       showUi(userInfoEntity);
    }
    private void showUi(UserInfoEntity userInfoEntity) {
        userInfoll.setVisibility(View.VISIBLE);
        userNameTv.setText(userInfoEntity.getUserName());
        ageTv.setText(userInfoEntity.getAge()+"岁");
        if (userInfoEntity.getSex()==0){
            sexTv.setText("性别:女");
        }else {
            sexTv.setText("性别:男");
        }
    }
    @Override
    public void onDataFailed(int code, String msg) {
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
    }

    @Override
    public int getLayoutId() {
        return R.layout.activity_login;
    }
}
  • Presenter层
public class LoginPresenter extends BasePresenter<ILoginView> {

    private LoginModel loginModel;
    public LoginPresenter(){
        loginModel=new LoginModel();
    }

    @Override
    public void onMvpSaveInstanceState(Bundle savedInstanceState) {

    }

    @Override
    public void onMvpDestroy() {

    }
    public void login(String account,String pwd){
      UserInfoEntity userInfoEntity= loginModel.login(account,pwd);
      getView().onDataSuccess(userInfoEntity);
    }
}

Demo地址 https://github.com/mrchengwenlong/design_demo

相关文章

网友评论

      本文标题:Android 之浅谈:MVC、MVP

      本文链接:https://www.haomeiwen.com/subject/wwqlgctx.html