Android TheMVP探索

MVP模式

MVP模式在Android中的应用已经越来越广了,总的来说,它可以Activity 代码变得更加简洁,方便进行单元测试,也可以避免 Activity 的内存泄露

按照MVC的分层,Activity和Fragment(后面只说Activity)应该属于View层,用于展示UI界面,以及接收用户的输入,此外还要承担一些生命周期的工作。Activity是在Android开发中充当非常重要的角色,特别是TA的生命周期的功能,所以开发的时候我们经常把一些业务逻辑直接写在Activity里面,这非常直观方便,代价就是Activity会越来越臃肿,超过1000行代码是常有的事,而且如果是一些可以通用的业务逻辑(比如用户登录),写在具体的Activity里就意味着这个逻辑不能复用了。如果有进行代码重构经验的人,看到1000+行的类肯定会有所顾虑。因此,Activity不仅承担了View的角色,还承担了一部分的Controller角色,这样一来V和C就耦合在一起了,虽然这样写方便,但是如果业务调整的话,要维护起来就难了,而且在一个臃肿的Activity类查找业务逻辑的代码也会非常蛋疼,所以看起来有必要在Activity中,把View和Controller抽离开来,而这就是MVP模式的工作了。

MVP模式的核心思想:

MVP把Activity中的UI逻辑抽象成View接口,把业务逻辑抽象成Presenter接口,Model类还是原来的Model。

这就是MVP模式,现在这样的话,Activity的工作的简单了,只用来响应生命周期,其他工作都丢到Presenter中去完成。从上图可以看出,Presenter是Model和View之间的桥梁,为了让结构变得更加简单,View并不能直接对Model进行操作,这也是MVP与MVC最大的不同之处。

传统MVP模式的弊端

普通MVP主要存在一下问题:

View和Model无法避免存在一定的耦合。
View难以复用
在Activity中很难避免一些数据的处理操作,比如用OnSaveInstanceState()去保存状态,用OnRestoreInstanceState()去恢复状态。

TheMVP原理介绍

既然知道了这些问题,我们的解决办法自然是不要将Activity作为View层而去单独包含Presenter类进来。反过来,我们将Activity(Fragment)作为Presenter层的代码,包含一个View层的类来。

使用Activity作为Presenter的优点就在于,可以原封不动的使用Activity本身的生命周期去处理项目逻辑,而不需要强加给另一个包含类,甚至记忆额外自定义的生命周期。

而同时作为独立的View层,我们的视图可以原封不动的传递给Presenter(不管是Activity或者Fragment),而不需要改任何代码。对于一个开发团队,完全可以将View层的东西交给一个人编写,而将业务实现交给另一个人编写。而随着逻辑变化对View的更改,只需要通过Presenter层的包含一个代理对象————ViewDelegate来操作相应的更改方法就够了。

与传统androidMVP不同(原因上文已经说了),TheMVP使用Activity作为Presenter层来处理代码逻辑,通过让Activity包含一个ViewDelegate对象来间接操作View层对外提供的方法,从而做到完全解耦视图层。如下图:

在这里插入图片描述

优化方式

TheMVP最大的特点在于关注View的复用性,解耦View与业务逻辑之间的关系。相应的,Presenter的复用性有较大欠缺。
为了解决Presenter的复用性(准确的说,应该是拆分粒度)问题,可以对TheMVP进行了扩展。

TheMVP 定制

将多个无activity的presenter挂载到以activity为载体的presenter中,同步activity的生命周期到无activity的presenter中。通过include或者ViewStub的方式在挂载layout到主activity presenter的layout中。
这意味着项目中存在两种p-v关系,有activity和无activity的(无activity的称为component presenter)。

结合DataBinding

一个好的架构一定是对扩展开放,对修改关闭的,这是软件设计模式的开闭原则。
如果你之前有了解过Google的DataBinding,你一定知道ViewModel的概念。DataBinding 解决了 Android UI 编程中的一个痛点,就是要给一个控件设置内容,必须首先获取到控件的对象,并调用set方法(例如setText()),传一个数据进去。
DataBinding允许你使用这样的代码为控件设置内容。

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{user.lastName}" />

其中user.lastName表示在项目中的数据类的user对象的lastName属性。

DataBinding存在的问题

另一方面,虽然databinding虽然简化了试图与数据绑定的代码,但同时也牺牲了布局文件的可复用性。例如我们经常会遇到的,一个Fragment与另一个Fragment,在布局上完全一样,而仅仅是数据不同,这时我们通常会用代码去控制在不同的界面显示不同的数据。然而,如果将数据写死在xml中,就失去了布局的复用性。

因此,我们可以尝试将视图与数据模型绑定的逻辑抽出,单独建立一个类来使用代码控制,这样如果发生相同的界面复用,只需要重写视图与数据绑定的逻辑就够了,其他的代码仍然不变。

定义一个ViewModel层的接口,其中包含两个泛型分别为View层的代理和Model层的代理:

public interface DataBinder<T extends IDelegate, D extends IModel> {
void viewBindModel(T viewDelegate, D data);
}

为Presenter添加扩展,使它能够支持DataBinder。其中使用getDataBinder()方法,得到开发中具体的某个界面的ViewModel层的扩展,然后我们只需要在数据改变的时候,手动调用notifyModelChanged()方法,即可使ViewModel中定义的绑定逻辑生效
在这里插入图片描述

进一步简化

之前的改进中,我们都需要通过一个databind对象来更改view界面,但在目前的客户sdk中,使用到的databind的数据比较少,实际上我们可以直接在delegate中对view进行更改,因此只需在delegate中提供一个对外开放的接口即可。

 public void setText(String text) {
        mEditText.setText(text);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值