android MVP——mvp架构的应用和优化

MVP架构在android还是很好用的。我也在试着将mvp用在项目中。

下面我就来说说mvp模式的应用和优化。

mvp模式的概念

MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。

比较

mvc:

1,在MVC里,View是可以直接访问Model的,View里会包含Model信息,不可避免的还要包括一些业务逻辑。

2,Model不依赖于View,但是View是依赖于Model。

3,有一些业务逻辑在View里实现了,导致要更改View也是比较困难的,至少那些业务逻辑是无法重用的。

mvp:

1,在MVP里,Presenter完全把Model和View进行了分离,主要的程序逻辑在Presenter里实现。

2,Presenter与具体的View是没有直接关联的,而是通过定义好的接口进行交互。从而使得在变更View时候可以保持Presenter的不变,即重用

3,应用程序的逻辑主要在Presenter来实现,其中的View是很薄的一层。这样一来就编写测试用的View,模拟用户的各种操作,从而实现对Presenter的测试

mvp的系统设计

我们先来个mvp系统的设计。(我们在这里模仿一个登陆的请求)

概要设计图

1,mobel层

mobel接口:规定操作数据的接口。

接口:IUserLoginMobel

/**
 * 用户操作接口 Model 业务层接口
 */
public interface IUserLoginMobel{
    /**
     * 用户登录
     *
     * @param name
     * @param pwd
     * @param loginListener
     */
    void login(String name, String pwd, OnLoginListener loginListener);
}

登录状态回调接口:

/**
 * 登陆状态接口
 */
public interface OnLoginListener {
    void loginSuccess(UserInfoBean user);

    void loginFailed(String message);
}

类:用户登陆操作类 UserLoginModel

/**
 * 用户登陆操作类,Model 业务层(接收数据,处理出局)
 */
public class UserLoginModel implements IUserLoginMobel {
    @Override
    public void login(final String name, final String pwd, final OnLoginListener loginListener) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                    if ("admin".equals(name) && "admin".equals(pwd)) {
                        UserInfoBean userInfoBean = new UserInfoBean();
                        userInfoBean.setUserId(System.currentTimeMillis());
                        userInfoBean.setUserName(name);
                        userInfoBean.setUserPwd(pwd);
                        loginListener.loginSuccess(userInfoBean);
                    } else {
                        loginListener.loginFailed("密码错误");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

2,Presenter层

定义 UserLoginPresenter类

/**
 * 用户登录的任命者。Presenter (用于接收模型发出的结果,给view层发送命令)
 */
public class UserLoginPresenter  {
    protected IUserLoginView mvcView;//view的接口
    private IUserLoginMobel userLoginMobel;//mobel的接口
    private Handler mHandler = new Handler();

    public UserLoginPresenter(IUserLoginView userLoginView) {
        this.mvcView = userLoginView;
        this.userLoginMobel = new UserLoginModel();//实例化用户登录业务层
    }

    public void login() {
        mvcView.showLoading();
        userLoginMobel.login(mvcView.getUserName(), mvcView.getPassword(), new OnLoginListener() {
            @Override
            public void loginSuccess(final UserInfoBean user) {
                //需要在UI线程执行
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mvcView.toMainActivity(user);
                        mvcView.hideLoading();
                    }
                });
            }

            @Override
            public void loginFailed(final String message) {
                //需要在UI线程执行
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mvcView.showFailedError(message);
                        mvcView.hideLoading();
                    }
                });
            }
        });
    }

    public void clear() {
        mvcView.clearPassword();
        mvcView.clearUserName();
    }
}

3,view 层

首相定义一个view接口 IUserLoginView

接口规定view层去实现的方法

/**
 * 完整的登陆接口。 View 接口
 */
public interface IUserLoginView {
    //获得用户信息
    String getUserName();

    String getPassword();

    //清除用户信息
    void clearUserName();

    void clearPassword();

    //遮罩层
    void showLoading();

    void hideLoading();

    //登陆成功
    void toMainActivity(UserInfoBean user);

    //登陆失败
    void showFailedError(String message);
}

我们定义一个MVCActivity来继承 IUserLoginView

/**
 * 这时候的activity相当于view (只负责显示数据)
 * Presenter与View交互是通过接口
 */
public class MVCActivity extends AppCompatActivity implements IUserLoginView {

    private EditText user_name_edit, user_pwd_edit;
    private Button user_login_btn, user_clear_btn;
    private ProgressBar user_login_bar;
    private UserLoginPresenter presenter;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        presenter=new UserLoginPresenter(this);
        initView();
    }

    private void initView() {
        user_name_edit = (EditText) findViewById(R.id.user_name_edit);
        user_pwd_edit = (EditText) findViewById(R.id.user_pwd_edit);
        user_login_btn = (Button) findViewById(R.id.user_login_btn);
        user_clear_btn = (Button) findViewById(R.id.user_clear_btn);
        user_login_bar = (ProgressBar) findViewById(R.id.user_login_bar);
        user_login_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                presenter.login();
            }
        });
        user_clear_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                presenter.clear();
            }
        });
    }

    @Override
    public String getUserName() {
        return user_name_edit.getText().toString();
    }

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

    @Override
    public void clearUserName() {
        user_name_edit.setText("");
    }

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

    @Override
    public void showLoading() {
        user_login_bar.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideLoading() {
        user_login_bar.setVisibility(View.INVISIBLE);
    }

    @Override
    public void toMainActivity(UserInfoBean user) {
        Toast.makeText(this, user.getUserName(), Toast.LENGTH_SHORT).show();
    }

    @Override
    public void showFailedError(String message) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
    }

}

还有layout.xml

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

    <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/user_name_edit"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </LinearLayout>

    <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/user_pwd_edit"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:orientation="horizontal">

        <Button
            android:id="@+id/user_login_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="登陆" />

        <Button
            android:id="@+id/user_clear_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="清除" />
    </LinearLayout>

    <ProgressBar
        android:id="@+id/user_login_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:visibility="invisible" />
</LinearLayout>

我们先来看看效果图。

可以看出,和我们原来用mvc设计的登陆达到了一样的目的。但是可以看出我们的activity再也没有像原来一样多了很多逻辑处理。

而我们的逻辑处理都放在了Presenter层。而activity成了一个真正的view。

这就是mvp架构最基本的应用。可以看出使用mvp去设计app可以很好的将activity当作一个view层分离出来。

那么从上面的结构图可以看出我们还是有很多可以优化的地方的。

优化

mobel层 接口都继承IBaseMobel接口

我们可以在IBaseMobel这个元接口中定义一些整个mobel都会做的工作,例如初始化数据

/**
 * presenter层基类接口
 */
public interface IBaseMobel {
    void initData();//定义一个所有presenter初始化数据的方法
}

同理:view层 接口都继承 IBaseView 接口

我们可以在IBaseView 这个元接口中定义一些整个mobel都会做的工作,例如初始化数据。

/**
 * view层基类接口
 */
public interface IBaseView {

    void initView();//view初始化view的一个基本接口
}

presenter层继承一个基类来收集重复方法或者属性

定义一个 BasePresenter类

/**
 * 在基类presenter中将添加和销毁方法提供
 */
public class BasePresenter<T> {

    protected T mvcView;

    /**
     * 每个继承基类的presenter都要去实现构造方法,并传入view层
     */
    protected BasePresenter(T mvcView) {
        this.mvcView = mvcView;
    }

    /**
     * 因为presenter层持有view层,所以,提供一个方法,在view层不使用的时候将对象释放
     */
    public void onDestroy() {
        mvcView = null;
    }
}

我们来看看如何让原来的UserLoginPresenter使用

修改后的UserLoginPresenter类

/**
 * 用户登录的任命者。Presenter (用于接收模型发出的结果,给view层发送命令)
 */
public class UserLoginPresenter extends BasePresenter<IUserLoginView> {

    private IUserLoginMobel userLoginMobel;//mobel的接口
    private Handler mHandler = new Handler();

    public UserLoginPresenter(IUserLoginView userLoginView) {
        super(userLoginView);
        //this.userLoginView = userLoginView;//未优化前的方法
        this.userLoginMobel = new UserLoginModel();//实例化用户登录业务层
    }

    public void login() {
        mvcView.showLoading();
        userLoginMobel.login(mvcView.getUserName(), mvcView.getPassword(), new OnLoginListener() {
            @Override
            public void loginSuccess(final UserInfoBean user) {
                //需要在UI线程执行
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mvcView.toMainActivity(user);
                        mvcView.hideLoading();
                    }
                });
            }

            @Override
            public void loginFailed(final String message) {
                //需要在UI线程执行
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mvcView.showFailedError(message);
                        mvcView.hideLoading();
                    }
                });

            }
        });
    }

    public void clear() {
        mvcView.clearPassword();
        mvcView.clearUserName();
    }

}

这样我们就把Presenter的初始化工作和关于activity在onDestory的时候手动置空Presenter中view对象(这时候的view对象其实就是activity)的方法给提取到基类中。

因为这两个方法很多地方会用到,所以我们不必每次都去写它们。

我们再将view层的activity封装。view层例如:fragment也是可以封装的。

我们建立一个抽象类BaseActivity。

/**
 * mvc模式的view层基类<继承 presenter 具体>
 */
public abstract class BaseActivity<T extends BasePresenter> extends AppCompatActivity {
    //必须实例化presenter对象
    public abstract T initPresenter();

    public T presenter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(setMvcView());
        presenter = initPresenter();
        initView();
    }

    protected abstract int setMvcView();

    protected abstract void initView();

    @Override
    protected void onDestroy() {
        presenter.onDestroy();
        super.onDestroy();
    }
}

接下来修改MVCActivity类

/**
 * 这时候的activity相当于view (只负责显示数据)
 * Presenter与View交互是通过接口
 */
public class MVCActivity extends BaseActivity<UserLoginPresenter> implements IUserLoginView {

    private EditText user_name_edit, user_pwd_edit;
    private Button user_login_btn, user_clear_btn;
    private ProgressBar user_login_bar;

    @Override
    public UserLoginPresenter initPresenter() {
        return new UserLoginPresenter(this);
    }

    @Override
    protected int setMvcView() {
        return R.layout.activity_main;
    }

    @Override
    protected void initView() {
        user_name_edit = (EditText) findViewById(R.id.user_name_edit);
        user_pwd_edit = (EditText) findViewById(R.id.user_pwd_edit);
        user_login_btn = (Button) findViewById(R.id.user_login_btn);
        user_clear_btn = (Button) findViewById(R.id.user_clear_btn);
        user_login_bar = (ProgressBar) findViewById(R.id.user_login_bar);
        user_login_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                presenter.login();
            }
        });
        user_clear_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                presenter.clear();
            }
        });
    }

    @Override
    public String getUserName() {
        return user_name_edit.getText().toString();
    }

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

    @Override
    public void clearUserName() {
        user_name_edit.setText("");
    }

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

    @Override
    public void showLoading() {
        user_login_bar.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideLoading() {
        user_login_bar.setVisibility(View.INVISIBLE);
    }

    @Override
    public void toMainActivity(UserInfoBean user) {
        Toast.makeText(this, user.getUserName(), Toast.LENGTH_SHORT).show();
    }

    @Override
    public void showFailedError(String message) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
    }

}

我们把activity的onCreate和onDestory交给基类来处理,我们也可以在基类中处理onResume等方法。所有的生命周期由基类来管理。

另外,我们将Presenter对象也交给基类来管理,让基类来处理Presenter对象中的公有方法。

mvp架构的应用和优化已经写完了,我们可以根据自己项目的实际情况作进一步的优化。

mvp其实就是一种设计思想。它不光用于对model、presenter和view的处理。这只是一种思想,可以用到很多地方。

更多的mvp模式可以去参照:

Google在Github开源的一个项目:Android Architecture Blueprints

简书:Android官方MVP架构项目解析

献上这篇博客的demo:

demo下载

时间: 2024-10-27 13:33:03

android MVP——mvp架构的应用和优化的相关文章

Android之MVP架构

MVP(Model View Presenter)模式是由MVC模式发展而来的,在如今的Android程序开发中显得越来越重要.本篇文章简单讨论了MVP模式的思想. 啥是MVP MVP模式的主要思想是将程序的业务逻辑从表现层分离出来,理想情况下,MVP模式可以使得相同的逻辑拥有完全不同且可互换的views. 为啥要用MVP 在Android实际开发过程中,我们会遇到这样的问题:Android中的activity与界面展示和数据访问机制耦合度非常高,既负责页面组件的展示,又负责处理业务逻辑.一个极

MVP架构-Android官方MVP项目和响应式MVP-RxJava项目架构分析对比解读

介绍 MVP这个架构一直是Android开发社区讨论的焦点,每个人都有自己的分析理解众说纷纭.直到GitHub上Google官方发布用MVP架构搭建的项目.感觉是时候分析了. MVP架构简介 这不是本文重点,所以摘抄自李江东的博文 MVP架构简介 对于一个应用而言我们需要对它抽象出各个层面,而在MVP架构中它将UI界面和数据进行隔离,所以我们的应用也就分为三个层次. View:对于View层也是视图层,在View层中只负责对数据的展示,提供友好的界面与用户进行交互.在Android开发中通常将A

Android官方MVP架构示例项目解析

前段时间Google在Github推出了一个项目,专门展示Android引用各种各样的MVP架构,算是官方教程了.趁着还新鲜,让我们来抛砖引玉一探究竟,看看在Google眼里什么样算是好的MVP架构. App架构在Android开发者中一直是讨论比较多的一个话题,目前讨论较多的有MVP.MVVM.Clean这三种.google官方对于架构的态度一直是非常开放的,让开发者自主选择组织和架构app的方式,期望能留给开发者更多的灵活性. 由于没有一套权威的架构实现,现在很多App项目中在架构方面都有或

适用android的MVP:如何组织展示层

原文 MVP for Android:How to organize presentation layer http://antonioleiva.com/mvp-android/ 译文 MVP(Model-View-Presenter)模式是著名的MVC(Model-View-Controller)模式的衍生.这段时间,MVP在Android应用开发上得到重视.越来越多的人讨论它,但是可靠的和结构化的信息仍然很少.这就是为什么我想利用这个博客鼓励这种讨论,并且把我们所知 以最好的方式应用到项目

Android设计模式——MVP

一.什么是MVP MVP:全称 Model-View-Presenter. MVP框架由3部分组成:View层负责显示,Presenter层负责逻辑处理,Model层提供数据. View:负责绘制UI元素.与用户进行交互(在Android中体现为Activity,Fragment) Model:负责存储.检索.操纵数据 Presenter:作为View与Model交互的中间纽带,处理与用户交互的负责逻辑. 二.创建Model Presenter View三个包 三.代码编写 1.View层代码

Android进阶-MVP

一.什么是MVP? MVP (Model View Presenter)模式由MVP模式演变而来,它将View层和逻辑层分离. 二.为什么使用MVP? 将View层和逻辑层分离后有利于拓展,比如当前代码属于来自本地数据库,如果需求变更数据来自网络,我们就不必重写整个View层.通过MVP我们将大部分逻辑抽出Activity,写在Presenter层.分层后就可以各司其职,也方便测试. 三.各层的职责. Presenter的职责:从Modle层获取数据经过处理后交给View层展示. View的职责

BAT大厂APP架构演进实践与优化之路

第1章 打车课程项目整体介绍课程介绍:介绍课程内容.教授方式,讲诉打车业务的整体架构思路:针对打车业务如何进行需求分析和工作量化评估,同时根据工作量化提出课程内容章节计划.1-1 lesson01-课程整体介绍导学 第2章 需求分析和工作量化讲解(在BAT大厂中)前后端 API .文档维护方法.平台.2-1 lesson02-需求分析与工作量化 第3章 项目规范与团队协作分享在BAT大厂中.项目支持是如何维护.保证代码质量的.然后实践,建立滴滴打车项目的代码规范.约定.3-1 lesson03-

Android之系统架构

Android 是Google开发的基于Linux平台的开源手机操作系统.它包括操作系统.用户界面和应用程序 —— 移动电话工作所需的全部软件,而且不存在任何以往阻碍移动产业创新的专有权障碍.Android采用WebKit浏览器引擎,具备触摸屏.高级图形显示和上网功能,用户能够在手机上查看电子邮件.搜索网址和观看视频节目等,比iPhone等其他手机更强调搜索功能,界面更强大,可以说是一种融入全部Web应用的单一平台.这里介绍Android的系统架构 android系统架构图 android的系统

Android存储系统的架构与设计

一.概述 本文讲述Android存储系统的架构与设计,基于Android 6.0的源码,涉及到最为核心的便是MountService和Vold这两个模块以及之间的交互.为了缩减篇幅,只展示部分核心代码. MountService:Android Binder服务端,运行在system_server进程,用于跟Vold进行消息通信,比如MountService向Vold发送挂载SD卡的命令,或者接收到来自Vold的外设热插拔事件.MountService作为Binder服务端,那么相应的Binde