Android中MVP架构分析(与MVC对比)

参考文章:浅谈 MVP in Android_Hongyang-CSDN博客_android mvp
本文出自:【张鸿洋的博客】

首先,MVP包括三层

M层指model:专门用于处理数据逻辑,类似于MVC中的M,像service,dao层之类的这些。

V层指View:处理视图层的一些控件的展示和隐藏等,负责View的绘制及与用户的交互,对应的实现就是Activity.类似于MVC中的V,html,jsp之类的

P层指Presenter:连接M层和V层,类似于MVC中的C,controller

贴代码详细介绍一下:

先看看布局文件吧

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="15dp">

    <EditText
        android:id="@+id/username"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="用户名"
        android:textSize="18sp"
        android:textColor="#000"/>
    <EditText
        android:id="@+id/password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="密码"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="15dp">
        <Button
            android:id="@+id/login"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="登陆"
            android:textSize="20sp" android:layout_marginRight="5dp"/>
        <Button
            android:id="@+id/clear"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="清除"
            android:textSize="20sp"
            android:layout_marginLeft="5dp"/>
    </LinearLayout>
    <ProgressBar
        android:id="@+id/progressbar"
        android:visibility="invisible"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>

bean包下的实体类

package com.example.mvptest1.bean;

/**
 * com.example.mvptest1.bean
 *
 * @author yueqingh
 * @date 2021/9/29
 */
public class User {
    private int uid;
    private String name;
    private String password;

    public User() {
    }

    public User(String name, String password) {
        this.name = name;
        this.password = password;
    }

    public User(int uid, String name, String password) {
        this.uid = uid;
        this.name = name;
        this.password = password;
    }

    public int getUid() {
        return uid;
    }

    public void setUid(int uid) {
        this.uid = uid;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "uid=" + uid +
                ", name='" + name + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

model下的接口:因为model层是处理数据逻辑的,所以,定义了

public void login(String name,String password,OnLoginListener loginListener);这个方法,根据这个方法去判断登陆是否成功,所以又定义了一个内部接口OnLoginListener,内部接口中定义了两个方法,分别代表登陆成功和登陆失败
package com.example.mvptest1.model;

import com.example.mvptest1.bean.User;

/**
 * com.example.mvptest1.model
 *
 * @author yueqingh
 * @date 2021/9/29
 */
public interface UserLoginModel {
    interface OnLoginListener{
        void loginSuccess(User user);

        void loginFailed();
    }
    public void login(String name,String password,OnLoginListener loginListener);
}

来看看model的实现吧,这里是没有对loginSuccess(User user)和loginFailed()进行实现的,因为登陆成功有一些view方面的东西需要实现,但是model又必须要和view分开,所以这里没有实现,将这两个方法交给了presenter去实现,因为presenter是连接model和view的。

package com.example.mvptest1.model.Impl;

import com.example.mvptest1.bean.User;
import com.example.mvptest1.model.UserLoginModel;

/**
 * com.example.mvptest1.model.Impl
 *
 * @author yueqingh
 * @date 2021/9/29
 */
public class UserLoginModelImpl implements UserLoginModel {

    @Override
    public void login(final String name, final String password, final OnLoginListener loginListener) {
        //模拟子线程耗时操作
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //模拟登陆成功
                if ("zhangsan".equals(name) && "admin".equals(password)){
                    User user = new User();
                    user.setName(name);
                    user.setPassword(password);
                    loginListener.loginSuccess(user);
                }else {
                    loginListener.loginFailed();
                }
            }
        }).start();
    }
}

model层看完了,我们看看view层,首先看看view层的接口,可以看到这个接口全都是与最前面的布局相关的,也就是view,没有涉及到数据逻辑。

package com.example.mvptest1.view;

import com.example.mvptest1.bean.User;

/**
 * com.example.mvptest1.view
 *
 * @author yueqingh
 * @date 2021/9/29
 */
public interface UserLoginView {
    //获取输入的用户名
    String getUsername();
    //获取输入的密码
    String getPassword();
    //显示进度条
    void showProgress();
    //隐藏进度条
    void hideProgress();
    //清除用户名的输入
    void clearUsername();
    //清楚密码的输入
    void clearPassword();
    //登陆成功的显示,用于项目的时候这里就可以用于Activity的跳转
    void toMainActivity(User user);
    //登陆失败的提示信息显示
    void showFailedError();
}

View的实现是在对应的Activity中实现的,但是我们要先把view和model的关系先建立起来,所以看一下代码

package com.example.mvptest1.presenter;

/**
 * com.example.mvptest1.presenter
 *
 * @author yueqingh
 * @date 2021/9/29
 */
public interface UserLoginPresenter {
    //登陆
    void login();
    //清除
    void clear();
}

presenter的实现

package com.example.mvptest1.presenter.Impl;

import android.os.Handler;

import com.example.mvptest1.bean.User;
import com.example.mvptest1.model.UserLoginModel;
import com.example.mvptest1.presenter.UserLoginPresenter;
import com.example.mvptest1.view.UserLoginView;


/**
 * com.example.mvptest1.presenter.Impl
 *
 * @author yueqingh
 * @date 2021/9/29
 */
public class UserLoginPresenterImpl implements UserLoginPresenter {

    //view
    private UserLoginView userLoginView;
    //model
    private UserLoginModel userLoginModel;
    private Handler handler = new Handler();
    //构造函数
    public UserLoginPresenterImpl(UserLoginView userLoginView, UserLoginModel userLoginModel) {
        this.userLoginView = userLoginView;
        this.userLoginModel = userLoginModel;
    }

    /**
     * 在点击登陆按钮时会调用这个方法,然后到model中处理数据逻辑,在view中进行对应的显示和隐藏
     */
    @Override
    public void login() {
        userLoginModel.login(userLoginView.getUsername(), userLoginView.getPassword(), new UserLoginModel.OnLoginListener() {
            @Override
            public void loginSuccess(final User user) {
                //需要在UI线程执行
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        userLoginView.toMainActivity(user);
                        userLoginView.hideProgress();
                    }
                });
            }

            @Override
            public void loginFailed() {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        userLoginView.showFailedError();
                        userLoginView.showProgress();
                    }
                });
            }
        });
    }

    /**
     * 点击清除按钮时,直接调用view的方法
     */
    @Override
    public void clear() {
        userLoginView.clearUsername();
        userLoginView.clearPassword();
    }
}

最后一步了,model的数据逻辑处理已经处理完毕,view的接口也建立完毕,再然后,model和view的关联也已经建立完毕,接下下我们就处理一些view的实现,在Activity中去调用presenter。

package com.example.mvptest1;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.example.mvptest1.bean.User;
import com.example.mvptest1.model.Impl.UserLoginModelImpl;
import com.example.mvptest1.presenter.Impl.UserLoginPresenterImpl;
import com.example.mvptest1.presenter.UserLoginPresenter;
import com.example.mvptest1.view.UserLoginView;

public class MainActivity extends AppCompatActivity implements UserLoginView, View.OnClickListener {

    private EditText usernameEt;
    private EditText passwordEt;
    private Button loginBtn;
    private Button clearBtn;
    private ProgressBar progressBar;
    //presenter
    private UserLoginPresenter userLoginPresenter;


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

        initViews();
    }

    private void initViews() {
        usernameEt = findViewById(R.id.username);
        passwordEt = findViewById(R.id.password);
        loginBtn = findViewById(R.id.login);
        clearBtn = findViewById(R.id.clear);
        progressBar = findViewById(R.id.progressbar);

        loginBtn.setOnClickListener(this);
        clearBtn.setOnClickListener(this);

        userLoginPresenter = new UserLoginPresenterImpl(this, new UserLoginModelImpl());
    }

    @Override
    public String getUsername() {
        return usernameEt.getText().toString();
    }

    @Override
    public String getPassword() {
        return passwordEt.getText().toString();
    }

    @Override
    public void showProgress() {
        progressBar.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideProgress() {
        progressBar.setVisibility(View.GONE);
    }

    @Override
    public void clearUsername() {
        usernameEt.setText("");
    }

    @Override
    public void clearPassword() {
        passwordEt.setText("");
    }

    @Override
    public void toMainActivity(User user) {
        Toast.makeText(MainActivity.this,"loginSuccess",Toast.LENGTH_SHORT).show();
    }

    @Override
    public void showFailedError() {
        Toast.makeText(MainActivity.this,"loginFailed",Toast.LENGTH_SHORT).show();
    }

    //根据id判断点击的是哪一个按钮
    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.login:
                userLoginPresenter.login();
                break;
            case R.id.clear:
                userLoginPresenter.clear();
                break;
                default:
                    break;
        }
    }
}

好了,就介绍到这里,写这个东西主要是为了后面回顾,这是我看了张鸿洋大佬的博客和其他很多人的博客最后的总结吧,代码几乎与张鸿洋的一致,没有特别大的改动,因为这个例子确实很生动,易懂,如有理解不到位的地方还请指正,如有侵权的地方,还请联系,立删

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值