Android中MVC、MVP、MVVM模式<一>

完整代码: https://github.com/fenggit/Lesson01-mvc-mvp-mvvm
效果图:
main

一. Android中的MVC模式

1. 对应关系
MVCMCV
全称ModelControllerView
含义模型控制层界面
对应Android的模块网络请求,数据库Activity、Fragment自定义View、layout布局(xml文件)
2. 关系图

mvc

3. 登录模块常见写法
  1. 登录模块功能:

    • 输入用户名和密码
    • 校验用户是否输入用户名和密码
    • 请求服务器
  2. 具体实现:
    login
    代码结构
    base
    具有实现

LoginActivity代码

public class LoginActivity extends AppCompatActivity {
    private EditText mUserView;
    private EditText mPasswordView;
    private Button mLoginView;

    private ProgressDialog mProgressDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        mUserView = (EditText) findViewById(R.id.et_user);
        mPasswordView = (EditText) findViewById(R.id.et_password);
        mLoginView = (Button) findViewById(R.id.btn_login);


        mLoginView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                login();
            }
        });
    }

    /**
     * 登录
     */
    public void login() {
        String user = mUserView.getText().toString();
        String pwd = mPasswordView.getText().toString();

        if (checkInput(user, pwd)) {
            mProgressDialog = ProgressDialog.show(this, null, "正在登录");

            // 模拟请求数据
            new Thread(new Runnable() {
                @Override
                public void run() {
                    // 假设请求数据1秒
                    SystemClock.sleep(1000);

                    // 更新UI
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            mProgressDialog.dismiss();
                            Toast.makeText(getBaseContext(), "登录成功", Toast.LENGTH_SHORT).show();
                        }
                    });

                }
            }).start();
        }

    }

    /**
     * 检查输入是否合法
     *
     * @param user
     * @param pwd
     * @return
     */
    public boolean checkInput(String user, String pwd) {
        if (TextUtils.isEmpty(user)) {
            Toast.makeText(this, "请输入用户名", Toast.LENGTH_SHORT).show();
            return false;
        }

        if (TextUtils.isEmpty(pwd)) {
            Toast.makeText(this, "请输入密码", Toast.LENGTH_SHORT).show();
            return false;
        }
        return true;
    }
}

布局代码activity_login.xml

<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:gravity="center_horizontal"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context="com.fenggit.lesson01.login.LoginActivity">

    <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="用户名:" />

        <EditText
            android:id="@+id/et_user"
            android:layout_width="match_parent"
            android:layout_height="48dp"
            android:hint="请输入用户名" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/email_login_form"
        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="密码:" />

        <EditText
            android:id="@+id/et_password"
            android:layout_width="match_parent"
            android:layout_height="48dp"
            android:hint="请输入密码"
            android:inputType="textPassword" />
    </LinearLayout>

    <Button
        android:id="@+id/btn_login"
        style="?android:textAppearanceSmall"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="登录"
        android:textAllCaps="false"
        android:textStyle="bold" />
</LinearLayout>

常规实现的问题
Activity类包含内容:网络请求+业务相关+界面相关
导致Activity类的庞大的,耦合度高,不利于扩展

4. 通过MVC模式改造登录模块

代码结构
mvc_class

剥离Activity中的网络请求模块到Model中,减轻Activity类的负担,这样Model层需要变更不需要变更Activity类

具有实现
将常规实现login()的实现更改为:

    /**
     * 登录
     */
    public void login() {
        String user = mUserView.getText().toString();
        String pwd = mPasswordView.getText().toString();

        if (checkInput(user, pwd)) {
            mProgressDialog = ProgressDialog.show(this, null, "正在登录");
            // 使用model层
            mLoginRequest.request(user, pwd, new LoginRequest.ResultListener() {
                @Override
                public void onSuccess() {
                    // 更新UI
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            mProgressDialog.dismiss();
                            Toast.makeText(getBaseContext(), "登录成功", Toast.LENGTH_SHORT).show();
                        }
                    });
                }

                @Override
                public void onFail() {

                }
            });
        }
    }

添加model模块,LoginRequest 请求数据类

public class LoginRequest {
    /**
     * 模拟请求网络数据
     *
     * @param user
     * @param pwd
     * @param resultListener
     * @return
     */
    public boolean request(final String user, final String pwd, final ResultListener resultListener) {
        // 模拟请求数据
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 假设请求数据1秒
                SystemClock.sleep(1000);
                Log.e("LoginRequest", "请求数据:" + user + "," + pwd);

                if (resultListener != null) {
                    // 密码和用户是123 则登录成功
                    if("123".equals(user)&&"123".equals(pwd)){
                        resultListener.onSuccess();
                    }else{
                        resultListener.onFail();
                    }
                }

            }
        }).start();

        return true;
    }

    public interface ResultListener {
        public void onSuccess();

        public void onFail();

    }
}

view模块可以自定义view,而Android中layout中xml就是view模块

MVC实现的问题
Activity类包含内容:业务相关+界面相关
总体来说减轻了Activity的职责,但是业务和界面还是在Activity模块中;

解决方式:
如果将Activity中的业务拆分–>MVP
如果将Activity中的界面控件拆分–>MVVM

二. Android中的MVP模式

1. 对应关系
MVPMVP
全称ModelViewPresenter
含义模型界面连接View和Model的桥梁
对应Android模块网络请求,数据库自定义View、layout布局(xml文件)业务逻辑

Presenter链接View和Model,使用接口进行隔离Activity业务和View.

2. 关系图

mvp

与MVC明显的特点就是View和Model不可以直接通信

3. 通过MVP模式改造登录模块

代码结构
mvp_class
其中:
LoginRequest为Model层,主要是网络请求相关;
LoginPresenter为Presenter层,主要是登录模块业务层
ILoginView为View层,主要是关联业务和UI操作,传递接口而不传递Activity和Fragment主要是为了通用性,Presenter业务操作完需要更新UI。
LoginActivity为纯界面相关操作,实现ILoginView接口

具有实现
其中LoginRequest和上面一样,Model不变;
添加Presenter层LoginPresenter业务层

public class LoginPresenter {
    private Context context;
    private LoginRequest mLoginRequest;
    // 这里传入接口,主要为了通用性,界面可能是Activity和Fragment
    private ILoginView mView;

    public LoginPresenter(Context context, ILoginView view) {
        this.context = context;
        this.mView = view;
        this.mLoginRequest = new LoginRequest();
    }

    /**
     * 登录
     *
     * @param user
     * @param pwd
     */
    public void login(String user, String pwd) {
        mLoginRequest.request(user, pwd, new LoginRequest.ResultListener() {
            @Override
            public void onSuccess() {
                // 登录成功,新UI
                mView.success();
            }

            @Override
            public void onFail() {
                // 登录失败,新UI
                mView.fail();
            }
        });
    }

    /**
     * 检查输入是否合法
     *
     * @param user
     * @param pwd
     * @return
     */
    public boolean checkInput(String user, String pwd) {

        if (TextUtils.isEmpty(user)) {
            Toast.makeText(context, "请输入用户名", Toast.LENGTH_SHORT).show();
            return false;
        }

        if (TextUtils.isEmpty(pwd)) {
            Toast.makeText(context, "请输入密码", Toast.LENGTH_SHORT).show();
            return false;
        }
        return true;
    }
}

添加View层接口ILoginView

public interface ILoginView {
    /**
     * 登录成功
     */
    void success();
    /**
     * 登录失败
     */
    void fail();
}

更改LoginActivity代码,此类只保留UI相关操作

public class LoginActivity extends AppCompatActivity implements ILoginView {
    private EditText mUserView;
    private EditText mPasswordView;
    private Button mLoginView;

    private ProgressDialog mProgressDialog;

    private LoginPresenter mLoginPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        mUserView = (EditText) findViewById(R.id.et_user);
        mPasswordView = (EditText) findViewById(R.id.et_password);
        mLoginView = (Button) findViewById(R.id.btn_login);

        // 第一个是Context对象,第二个是ILoginView
        mLoginPresenter = new LoginPresenter(this, this);

        mLoginView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                login();
            }
        });
    }

    /**
     * 登录
     */
    public void login() {
        String user = mUserView.getText().toString();
        String pwd = mPasswordView.getText().toString();

        if (mLoginPresenter.checkInput(user, pwd)) {
            mProgressDialog = ProgressDialog.show(this, null, "正在登录");
            mLoginPresenter.login(user, pwd);
        }
    }

    public void success() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mProgressDialog.dismiss();
                Toast.makeText(getBaseContext(), "登录成功", Toast.LENGTH_SHORT).show();
            }
        });
    }

    public void fail() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mProgressDialog.dismiss();
                Toast.makeText(getBaseContext(), "登录失败", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

MVP实现的问题
主要就是分解Activity职责,原本Activity包含:网络请求+业务相关+界面相关等三个模块,现在完全解耦合;网络请求数据由model层处理,业务相关由presenter处理,而界面View层由Activity处理UI和layout中xml布局;

三. Android中的MVVM模式

未完待续,见下一篇博客

完整代码: https://github.com/fenggit/Lesson01-mvc-mvp-mvvm

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值