您的位置:首页 > 运维架构 > 网站架构

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

2015-11-20 19:27 676 查看

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

开篇简介:探险系列,是我对当前的一些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。

下图可以显而易见的看出来



在传统的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 java