Android 架构设计实现——MVP模式

转载请注明出处:http://blog.csdn.net/smartbetter/article/details/70853135

随着 UI 创建技术的功能日益增强,UI 层也履行着越来越多的职责。为了更好地细分视图(View)与模型(Model)的功能,让 View 专注于处理数据的可视化以及与用户的交互,同时让 Model 只关系数据的处理,基于 MVC(Model View Controller) 模式的 MVP(Model-View-Presenter) 模式应运而生。目前MVP模式在 Android 应用开发中越来越重要了,大家也都在讨论 MVP 的理论,体系化的资料非常少,所以诞生出了本篇文章。MVP 模式是 MVC 模式的一个演化版本,MVP 模式能有效降低 View 的复杂度,避免业务逻辑被塞进 View 中,MVP 模式会解除 View 与 Model 的耦合,同时又带来了良好的可扩展性、可测试性。

MVP 模式可以分离显示层和逻辑层,它们之间通过接口进行通信,降低耦合。理想化的 MVP 模式可以实现同一份逻辑代码搭配不同的显示界面,因为它们之间并不依赖于具体,而是依赖于抽象,这使得 Presenter 可以运用于任何实现了 View 逻辑接口的 UI,使之具有更广泛的适用性,保证了灵活度。

1.MVP模式的三种角色

角色 说明
Model 主要做一些数据处理, 网路请求。Presenter 需要通过 Model 层存取、获取数据,Model是封装了数据库 Dao 层或者网络获取数据的角色,或者两种数据获取方式的集合。
Presenter 交互中间人,核心逻辑,处理 View 的业务逻辑,沟通 View 和 Model 的桥梁,Presenter 持有的 View、Model 引用都是抽象,它从 Model 层检索数据后返回给 View 层,使得 View 和 Model 没有耦合,也将业务逻辑从 View 层抽取出来,经常会执行耗时操作。
View 用户界面,Activity、Fragment 或者某个 View 控件,含有一个 Presenter 成员变量,通常 View 层需要实现一个逻辑接口,将 View 上的操作通过会转交给 Presenter 进行实现,最后 Presenter 调用 View 逻辑接口将结果返回给 View 元素。

很多缺乏经验的工程师很可能会将各种各样的业务逻辑塞进某个 Activity、Fragment 或者自定义控件中,使得这些组件的单个类型臃肿不堪。MVP 模式可以让 UI 界面和数据分离,职责单一,易于维护。MVP 模式也并不是一个标准化的模式,它有很多实现方式,我们也可以根据自己的需求和自己认为对的方式去修正 MVP 的实现方式,它可以随着 Presenter 的复杂程度变化。只要保证我们是通过 Presenter 将 View 和 Model 解耦合、降低类型复杂度、各个模块可以独立测试、独立变化,这就是正确的方向。

2.实际项目中MVP模式的实现

MVP 模式的实现我们以最简单的用户登录为例进行说明。MVP 模式一个很大特点就是定义接口比较多,代码量变大,下面来看一下实际项目中MVP模式的实现。

首先定义 MVP 基本的三个接口,基本上是固定写法:

public interface IModel {
}
public interface IPresenter<V extends IView> {
    /**
     * 绑定
     * @param view
     */
    void attachView(V view);
    /**
     * 防止内存的泄漏, 清除Presenter与Activity之间的绑定
     */
    void detachView();
    /**
     * @return 获取View
     */
    V getIView();
}
public interface IView {
}

然后定义契约类,定义 Presenter、View 用到的一些接口方法:

public class LoginContract {
    public interface LoginView {
        String getUserName();
        String getPwd();
        void loginSuccess(LoginBean loginBean); // 登录成功,展示数据
        void loginFail(String failMsg);
    }
    public interface LoginPresenter {
        void login(String name, String pwd); // 业务逻辑
    }
}

定义 LoginModel 类,主要做一些数据处理, 网路请求:

public class LoginModel extends BaseModel {
    private boolean isLogin = false;
    public boolean login(@NonNull String username, @NonNull String pwd, @NonNull final DataListener
            listener) {
        // 此处推荐使用 RxJava + Retrofit 进行网络请求
        // 网络请求成功 isLogin = true; listener.successInfo(articles);
        // 网络请求失败 isLogin = false; listener.failInfo(str);
        return isLogin;
    }
    // 通过接口产生信息回调
    public interface DataListener<T> {
        void successInfo(T result);
        void failInfo(String result);
    }
}

LoginModel 的父类:

public class BaseModel implements IModel {
    // 做一些数据处理, 网路请求的初始化操作
}

然后定义交互中间人 LoginPresenter,处理 View 的业务逻辑,它是沟通 View 和 Model 的桥梁,Presenter 持有的 View、Model 引用都是抽象,且经常会执行耗时操作:

public class LoginPresenter extends BasePresenter<LoginActivity> implements
        LoginContract.LoginPresenter {
    @Override
    public void login(String name, String pwd) {
        if (!getIView().checkNull()) {
            ((LoginModel) getiModelMap().get("login")).login(name, pwd, new LoginModel
                    .DataListener<LoginBean>() {
                @Override
                public void successInfo(LoginBean result) {
                    getIView().loginSuccess(result); // 成功
                }

                @Override
                public void failInfo(String result) {
                    getIView().loginFail(result); // 失败
                }
            });
        }
    }
    @Override
    public HashMap<String, IModel> getiModelMap() {
        return loadModelMap(new LoginModel());
    }
    @Override
    public HashMap<String, IModel> loadModelMap(IModel... models) {
        HashMap<String, IModel> map = new HashMap<>();
        map.put("login", models[0]);
        return map;
    }
}

Presenter 如果持有 Activity 的强引用,在请求结束之前 Activity 被销毁了,那么由于网络请求还没有返回,导致 Presenter 一直持有 Activity 对象,使得 Activity 无法被回收,此时就容易发生内存泄漏,解决这个问题需要通过弱引用来解决,LoginPresenter 的父类 BasePresenter 如下:

public abstract class BasePresenter<V extends IView> implements IPresenter {
    private WeakReference<V> mViewRef; // View接口类型的弱引用
    /**
     * 建立关联
     * @param iview
     */
    @Override
    public void attachView(IView iview) {
        mViewRef = new WeakReference(iview);
    }
    /**
     * 解除关联
     */
    @Override
    public void detachView() {
        if (mViewRef != null) {
            mViewRef.clear();
            mViewRef = null;
        }
    }
    /**
     * 获取View
     * @return
     */
    @Override
    public V getIView() {
        return mViewRef.get();
    }
    /**
     * 判断是否与View建立了关联
     * @return 建立则返回true
     */
    public boolean isViewAttached() {
        return mViewRef != null && mViewRef.get() != null;
    }
    public abstract HashMap<String, IModel> getiModelMap();
    /**
     * @param models
     * @return
     * 添加多个model,如有需要
     */
    public abstract HashMap<String, IModel> loadModelMap(IModel... models);
}

到这里,Model 和 Presenter 已经都有了,还差 View。Activity 实现需要 IView 和 LoginContract.LoginView 接口,并需要建立与 Presenter 之间的联系,Activity 的业务逻辑都将交给 Presenter 进行处理,处理结果通过 LoginContract.LoginView 接口回调给 Activity 类:

public class LoginActivity extends AppCompatActivity implements IView, LoginContract.LoginView {
    LoginPresenter mPresenter;
    // 代码省略
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        if (mPresenter != null) {
            mPresenter.attachView(this);
        }
        // 代码省略
        // 请求数据,当请求成功后,调用 LoginContract.LoginView 的 loginSuccess 方法将数据传递给 View
        mPresenter.login(getUserName(), getPwd());
    }
    // 代码省略
    @Override
    public void loginSuccess(LoginBean loginBean) {
        // 更新UI
    }
    @Override
    public void loginFail(String failMsg) {
    }
    /**
     * 注意MVP与Activity、Fragment生命周期的处理
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mPresenter != null) {
            mPresenter.detachView();
        }
    }
}

此时 MVP 的关系此时已经建立成功了。Activity 此时的作用只是做一些 View 的初始化工作,职责单一、功能简单、易于维护。此外,Presenter 与 Model 也依赖于抽象而不是具体,使得 Model 的具体实现可以被轻易地替换。Presenter 与 View 的低耦合使得系统能够应对 UI 的易变性问题,也使得系统的 View 模块变得易于维护。最后 Activity 在实际开发中也会向上抽取出 BaseActivity,比较简单,这里不再给出。

另外基于 MVP 架构,结合 RxJava、Retrofit、OkHttp编写了一个开源框架,易理解,深度解耦,方便迭代。

开源地址:https://github.com/smartbetter/MvpRxJavaRetrofitOkhttp,欢迎Follow、Fork、Star。

时间: 05-03

Android 架构设计实现——MVP模式的相关文章

Android架构设计和软硬整合完整训练:HAL&amp;Framework&amp;Native Service&amp;Android Service&amp;Best Practice

如何理解Android架构设计的初心并开发出搭载Android系统并且具备深度定制和软硬整合能力特色产品,是本课程解决的问题. 课程以Android的五大核心:HAL.Binder.Native Service.Android Service(并以AMS和WMS为例).View System为主轴,一次性彻底掌握Android的精髓. 之所以是开发Android产品的必修课,缘起于: 1, HAL是Android Framework&Application与底层硬件整合的关键技术和必修技术: 2

Android架构设计和软硬整合:HAL&amp;Framework&amp;Native Service&amp;Android Service&amp;Best Practice

如何理解Android架构设计的初心并开发出搭载Android系统并且具备深度定制和软硬整合能力特色产品,是本课程解决的问题. 课程以Android的五大核心:HAL.Binder.Native Service.Android Service(并以AMS和WMS为例).View System为主轴,一次性彻底掌握Android的精髓. 之所以是开发Android产品的必修课,缘起于: 1, HAL是Android Framework&Application与底层硬件整合的关键技术和必修技术: 2

Android架构设计和软硬整合完整训练:HAL&amp;Framework&amp;Native Service&amp;Android Service&amp;Best Practice

如何理解Android架构设计的初心并开发出搭载Android系统并且具备深度定制和软硬整合能力特色产品,是本课程解决的问题. 课程以Android的五大核心:HAL.Binder.Native Service.Android Service(并以AMS和WMS为例).View System为主轴,一次性彻底掌握Android的精髓. 之所以是开发Android产品的必修课,缘起于: 1,     HAL是Android Framework&Application与底层硬件整合的关键技术和必修技

Android架构设计和软硬整合完整训练

Android架构设计和软硬整合完整训练:HAL&Framework&Native Service&Android Service&Best Practice 如何理解Android架构设计的初心并开发出搭载Android系统并且具备深度定制和软硬整合能力特色产品,是本课程解决的问题. 课程以Android的五大核心:HAL.Binder.Native Service.Android Service(并以AMS和WMS为例).View System为主轴,一次性彻底掌握An

王家林最受欢迎的一站式云计算大数据和移动互联网解决方案课程 V3之Android架构设计和实现完整训练:HAL&amp;Framework&amp;Native Service&amp;Android Service&amp;Best Practice

如何理解Android架构设计的初心并开发出搭载Android系统并且具备深度定制和软硬整合能力特色产品,是本课程解决的问题. 课程以Android的五大核心:HAL.Binder.Native Service.Android Service(并以AMS和WMS为例).View System为主轴,一次性彻底掌握Android的精髓. 之所以是开发Android产品的必修课,缘起于: 1,  HAL是Android Framework&Application与底层硬件整合的关键技术和必修技术:

浅谈android架构设计

到目前为止,android开发在网络上或者社区上没有公认的或者统一的开发框架,好多框架都是基于对方法的封装.今天在这浅谈两年来对android开发的理解,主要是思想上的理解,希望对大家有帮助. 我认为android开发可以从两个方面去总结架构的设计,在这里对于实现只做陈述: 一,就是大多数人的设计思路,对方法的封装. 在这里我根据开发的习惯对工程进行包的设计: 1. http:网络请求方法封装.这里建议采用线程+Handler的模式,把Http 中get方法和post两种请求方式分开,对于正常的

Android的一种MVP模式框架

今天给大家分享的是一种将view的初始化和逻辑与activity分离的架构,采用的是mvp模式.但令人遗憾的是,这仅仅是一个新的思路,我在实际使用中发现其并不能完全将UI逻辑与activity分开,所以在实际中没办法认为这种设计是合理的.设计的初衷是觉得activity要接收intent或者要进行很多其他的处理,很难让人认为activity是一个与View相关的类,所以我们的想法是将view的逻辑从activity中分离,这种分离的方式我们就要用到一个UI类的接口.这个思路来自:https://

Android架构设计之插件化、组件化

如今移动app市场已经是百花齐放,其中有不乏有很多大型公司.巨型公司都是通过app创业发展起来的:app类型更加丰富,有电子商务.有视频.有社交.有工具等等,基本上涵盖了各行各业每个角落,为了更加具有竞争力app不仅功能上有创性,内容也更加多元化,更加饱满,所以出现了巨大的工程.这些工程代码不停添加如果没有一个好的架构所有代码将会强耦合在一起,功能直接也会有很多依赖,那么就会出现很多问题:例如: 1.修改功能困难,牵一发动全身.很多地方如果api写的不好,封装不优雅,那么就会出现改一个地方需要改

【Android - 框架】之MVP模式的使用

提起MVP架构模式,大家可能首先想到的是它的"前辈"MVC模式.MVC由Model.View.Controller组成,请求从Controller进入后进行业务判断,然后交给Model或View进行处理.这本身没什么,但是应用在Android程序中时,大家就会发现,Activity既担任了Controller的角色进行业务筛选,又担任了View的角色进行界面展示,甚至有些时候还会担任Model的角色加载数据.这就使的Activity中的代码变得很多很长,而且功能杂乱,不便区分.怎么办呢