架构探险——Android MVP模式浅析

原创 2015年11月20日 19:27:57

“善苑国尝贡一蟹,长九尺,有百足四螯,因名百足蟹。煮其壳胜于黄胶,亦谓之螯胶,胜凤喙之胶也。”——东汉郭宪撰的《汉武洞冥记》· 卷三

开篇简介:探险系列,是我对当前的一些Android项目架构,或框架的一些分析与探索。Android到目前为止还未有像Java Web一样有成熟的一套框架,无数的开发者都在暗夜中摸索着。也希望借本篇让读者做一个勇于吃螃蟹的人,有天亦能成为第一个吃螃蟹的人。


Android经典架构——MVP

之所以说它的经典,是因为在此之前,Android还处于一个混沌的阶段,在一些公司里,所有的操作都写在一个Activity或Fragment里,代码冗余,耦合度极高。打开一些关键页面,代码洋洋洒洒4000+。好一首长恨歌!对后面新进员工而言,维护成本太高了。

MVP的出现,不亚于盘古开天辟地般的举措。终于有一个层级分级明显、高度可复用、耦合度低的架构模式出现。于我的震撼不亚于当初学习Servlet的时候发现SSH这种整合框架的程度,当然后面也有Google自己推荐的MVVM(Data Binding )。这是后话,本系列之后也会为大家讲解。

介绍MVP前也应该给大家普及一下概念。关于概念,我想就是你的明白原理之后的对其的总结。这个我在巨人系列说过了,不撮我的痛点了…..

概念:MVP是经典架构MVC的继承与延伸。它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示展示。二者也有也有不同的地方:在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会从直接Model中读取数据而不是通过 Controller。

下图可以显而易见的看出来
MVP与MVC对比图

在传统的Java Web中,MVC再适合不过了,Controller只是负责什么样的View需要什么样的数据,然后去Model里找,最后让Model自己与View层交互而已,实现了显示与逻辑分开

而在Android中,我们可以勉强理解为它已经是一个MVC模式了。注意只是从某个角度来看,因为从别的角度出发,它并不是。

层级 描述
视图层(View) 一般采用XML文件进行界面的描述,使用的时候可以非常方便的引入。类似HTML的结构
控制层(Controller (一部分的View)) Android的控制层的重任通常落在了众多的Acitvity的肩上,不过其实也肩负着一大部分对View的操作,因此不能算是严格的MVC
模型层(Model) 对数据库的操作、对网络等的操作都应该在Model里面处理。


Android 设计之初,愿景是美好的。不过其实作为移动端,本质上与前端没什么区别。最多的还是Modle对View的动态控制。当然同时还有View的一些监听事件的响应。

同时,Java从来也不是一门简洁轻便的语言,即使加入了lambda。而且还有findViewById这种东西在。一个稍微复杂的页面仅仅初始化View控件就要好多行代码。这也是类似Butterknife这类框架存在的原因。

于是我们在一个Activity或者Fragment上一般要做如下几件事:
1. 初始化View控件
2. 维护控件View和Modle层的逻辑
3. 处理数据层,如果你没有将之独立出去处理的话。(其实也只是几个回调就能解决的。不过很多人还是喜欢写在Activity和Fragment中,不过有时候也是为了维护项目的完整性,不能就你搞特殊是吧。XD)
4. 其他逻辑,假如打点,传递数据,维护生命周期等。

可以看出,我们Activity与Fragment里做的事真的很多。项目维护的难易程度会随着项目周期而线性增长,这样维持下去,一个页面出现4000+的代码量不足为奇。

一个好的架构,是能将这种增长尽可能的降低。


因此,我们最需要的其实不是将Model层移出去(其实一样很需要,不过优先级可以低一点)。而是将我们的控制逻辑给移出Activity。将Activity从Controller层、部分View层的角色变成单纯View层。这样是不是会变得很逻辑明了,结构清晰?

MVP的引入由此而来。

试想一下,我们Activity只是一个View层,它只要知道什么情况下View要什么事。而什么时候要做,就不由Activity控制了。

概念说完了。大家可以细心比较下。二者的区别。接下来,我就用一个简单的demo来为大家展示一下,mvp的魅力。

那先休息一下吧~,先吸收下上面的知识点。

架构探险,不是说该如何使用某某架构,而是说出里面的思想,授人以渔。


以上说了我们的MVP,可不是The Most Value Player…..

现在我将讲诉如何搭建一个MVP工程架构。很多做Java Web的人看不起Android开发人员,首先,觉得android简单,其次,毫无架构可言,很多情况下,都不面向接口编程,只为了实现而编程

MVP的架构则是面向接口编程。如果你浸淫Java web的技巧,那MVP对你而言,不是什么复杂的架构。如果你只会Android,并如我一样是一个菜鸡,那就需要慢慢理顺,消化它,并自己写出自己的demo。

然后我先做一个东西瞧瞧看:
点击一个button,它会访问百度首页,然后show到我们的TextView上。
效果图如下(中间有showDialog,太快了。。。截不下来):
初始情况:
这里写图片描述
点击情况
这里写图片描述

看看我们所需要的材料:

原料 描述
StringView(接口) 定义着我们当前Activity(View)的行为
StringPresenter(类) 定义着Activity(View)与Presenter层交互的方法(比如传参)
调用Activity的方法
处理Model层返回数据
StringModel(类) 实现我们的数据请求
OnStringListener(只是数据返回的回调而已,用了事件总线。你完全可以不用它) 数据返回之后的回调,回调给Presenter层

(注意:这个只是最最简单的食材,最最普通的味道。最好的是将现有的类上再定义一个接口,定义一个规范。这样划分的粒度可以很容易的复用。听不明白没有关系,慢慢实践,你会越来越明白)


接下来直接看我们的Demo

没有太详细的注释,因为真的不难
没有太详细的注释,因为真的不难
没有太详细的注释,因为真的不难

重要的事情说三遍!!!

/**
 * Created by zhangyanye on 2015/8/23
 * Description:获取String时,定义的行为。我们的Activity将会实现这个接口
 */
public interface StringView {

    void showString(String result);

    void showLoding();

    void hideLoding();

}


/**
 * 作为数据层的回调,被Presenter实现,可被事件总线框架取代。
 */
public interface OnStringListener {
    /**
     * 成功时回调
     *
     * @param result
     */
    void onSuccess(String result);

    /**
     * 失败时回调,简单处理,没做什么
     */
    void onError(VolleyError error);
}


/**
 *  简单的用封装后的volley来请求网络,只要知道是请求了数据就好了。详细的可以看  看我的github,有我对Volley+gson+OkHttp的封装
 */
public class StringModleImpl {

     /**
     *  看到没有!!  传入了我们的回调listener
     */
    @Override
    public void load(String url, final OnStringListener listener) {
        /*数据层操作 */
        VolleyRequest.RequestGet(Request.Method.GET, 0, url, "test",
                new VolleyListener(FreeWalkerApplication.getApp(), new ResponseListener<String>() {
                    @Override
                    public void OnSuccess(String result) {
                        listener.onSuccess(result);
                    }

                    @Override
                    public void OnError(VolleyError error) {
                        listener.onError(error);
                    }
                }));
    }


/**
 * Created by zhangyanye on 2015/11/19
 * Description:Presenter作为中间层,持有View和Model的引用,对model层的数据进行处理,控制View层的展示
 */
public class StringPresenter implements OnStringListener {

    private StringView stringView;
    private CommonModel commonModel;

    public StringPresenter(StringView stringView) {
        this.stringView = stringView;
        commonModel = new StringModleImpl();
    }

    /**
     *   对View层提供方法
     */
    public void setUrl(String url) {
        stringView.showLoding();
        commonModel.load(url, this);
    }

    //model 回调  
    @Override
    public void onSuccess(String result) {
        stringView.hideLoding();
        stringView.showString(result);
    }
    //model 回调
    @Override
    public void onError(VolleyError error) {
        stringView.hideLoding();
        stringView.showString(error.getMessage());
    }
}


public class MainActivity extends Activity implements StringView {

    private TextView textView;
    private StringPresenter stringPresenter;
    private Dialog dialog;
    private Button button;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化Persenter
        stringPresenter = new StringPresenter(this);
        initView();
    }

    private void initView() {
        textView = (TextView) findViewById(R.id.txt);
        dialog = new Dialog(this);
        button = (Button) findViewById(R.id.btn);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stringPresenter.setUrl("http://wwww.baidu.com/");
            }
        });

    }

    @Override
    public void showString(String result) {
        textView.setText(result);
    }

    @Override
    public void showLoding() {
        dialog.show();
    }

    @Override
    public void hideLoding() {
        dialog.hide();
    }

}

嗯哈。代码就是这样了。简单的几个类,我就不画流程图了,看的不太明白,就跟着Button的OnClick事件走一遍,就能明白了

附上我的github的 源码地址。喜欢的话,记得给颗星星哈! 2333333333~


思考部分

1. 那问题来了!你丫的把这些东西抽取来了,那你想干嘛??好!那我和你说。

比如,我有三种请求。1. 收藏请求的;2. 刷新页面数据请求;3. 购买请求;
假如你粒度分的够细,将每一个部分都隔离出来。对应着相对MVP。等于是有多套(最多也就三套)这样的Class。

不好的地方时,你的类变得多了,不过包名取得好,不是什么问题。
好的地方是,你不用重复造轮子了,View层随着Activity或者Fragment会变。可是我们的处理逻辑是不变的。这样我们就可以不用重复造轮子了。

如果你分的不够细,一个页面对应的MVP处理着所有的请求。也能让代码可读性更高,容易维护

2.可能你会想,我当前的项目已经都成型了。4000+代码已经有了,这MVP对我有啥子用处。how to change it?go die?
其实,当你有一个class已经有4000+的代码的时候,说明你的项目已经一定的规模,尝试着分出module,对你的代码可维护性也有一定的提升。在独立的module中尝试使用MVP重构你的4000+class,特别针对业务相似的页面。我想会很有效的改善你的当前的困局。
顺口一提,我不提倡在业务相近的页面使用继承。尽管节约的代码量。可是,降低了代码的可扩张,维护性。


没有什么好与不好,一切只有适不适合。再美的女孩,你不喜欢。也是拉倒。


总结:我本以为有了官方data binding之后,MVP应该会冷了不少。没成想,MVP如今大行其道,很多人都在讨论。除了无需任何的框架,之外,也在于它高度的可扩展性。很多人在其之上进行了深度的改版。所以以它为开篇,我想再适合不过了~

就这样~希望能对大家有帮助!!

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

Android点击应用Icon发生了什么

Android点击应用Icon发生了什么 分析应用的启动

Android FrameWork——Touch事件派发过程详解

对于android的窗口window管理,一直感觉很混乱,总想找个时间好好研究,却不知如何入手,现在写的Touch事件派发过程详解,其实跟android的窗口window管理服务WindowManag...
  • stonecao
  • stonecao
  • 2011年09月08日 15:07
  • 56528

Android——MVP架构模式之入门demo

什么是MVP?MVP(Model - View - Presenter , 模型 - 视图 - 表示器)模式则是由IBM开发出来的一个针对C++和java的编程模型,大概出现于2000年,是MVC模式...

浅析MVP(Model-View-Presenter)架构及开发模式

一、概述 MVC模式已经出现了几十年了,在GUI领域已经得到了广泛的应用,由于微软ASP.NET MVC Framework的出现,致使MVC一度成为.NET社区的热名话题。作为MVC的变种MVP模式...

Android MVP架构浅析

MVP从更早的MVC架构演变过来的,与MVC有一定的相似:(1)MVC的缺点:在Android开发中,Activity并不是一个标准的MVC模式中的Controller,它的首要职责是加载页面布局和初...

MVX Android设计架构浅析-MVP

简介MVX Android设计架构浅析-MVC 读过这篇文章以后,应该对MVC框架有个大概的了解,这也是大部分Android应该的常用框架,但是这种框架给人的感觉更像是 View-Module框架,因...

Android开发中MVP模式浅析

浅析 android MVP
  • CHZiroy
  • CHZiroy
  • 2015年05月09日 11:38
  • 1576

浅析android的mvp模式

MPV 是从经典的MVC模式演变过来的,其基本思路都是相通的。       MVP是模型(Model)、视图(View)、控制者(Presenter)的缩写,分别代表项目中3个不同的模块。     ...

Android MVP 模式 理解与浅析

MVP模式 MVC模式 差异
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:架构探险——Android MVP模式浅析
举报原因:
原因补充:

(最多只允许输入30个字)