MVP
Last updated
Was this helpful?
Last updated
Was this helpful?
由于MVP被动视图的特性, Presenter会引用View的抽象以及Model的抽象, 同时View会引用Presenter, 那么此时几乎每个界面都会多出很多声明, 初始化的重复语句. 要消除这些重复可以考虑使用依赖注入的框架, 如Dagger, 但是考虑到Dagger本身的复杂性, 以及项目复杂度等原因, CoreLibs采用泛型及模板方法来消除重复.
基本上Android中是由Activity和Fragment来承载视图, 也有可能是View/ViewGroup. 因此在CoreLibs中提供了BaseActivity以及BaseFragment两个模板类, 来处理一些公共的视图逻辑. 至于View/ViewGroup的模板类会在以后加入. 模板类, 不仅可以简化代码, 同时也能起到一定的约束作用, 比如将onCreate方法拆分成多个符合单一职责原则的小方法, 从而避免onCreate过于臃肿.
被动视图中的View是将界面行为抽象出来的接口, 以供Presenter调用. 同Base模板类一样, View也可以抽象出几乎所有界面所共有的行为 -- BaseView. 比如只要有网络请求的界面(项目中几乎都是), 都会有加载框来提示用户当前正在加载网络数据, 加载完成后需要隐藏加载框, 并在适当时候提示用户一些错误消息. 一旦抽象出来BaseView, 就可以在Presenter等类里自动的调用这些公共的行为, 而无需再重复手动写.
Presenter的共有逻辑一般就是与界面的绑定, 解绑等.
Model这一层比较复杂, 随着项目的复杂度, Model可能会继续划分层级, 因此暂时没有抽出共有的逻辑.
View与Presenter之间是通过泛型来约束类型, 这里View以BaseActivity为例, BaseFragment与其类似.
BaseActivity声明
public abstract class BaseActivity<V extends BaseView, T extends BasePresenter<V>>
BasePresenter声明
public abstract class BasePresenter<T extends BaseView>
BaseView声明
public interface BaseView
可以看到, BaseActivity需要两个泛型, 第一个是继承自BaseView的接口, 第二个是继承自BasePresenter的Presenter, 同时Presenter里的泛型必须是V类型, 也就是第一个泛型类型.
BasePresenter则只需要一个继承自BaseView的接口.
这样做是为了约束View与Presenter的类型, 可以强制开发使用MVP模式, 同时可以将一些通用逻辑被抽象到BaseActivity与BasePresenter中:
BaseActivity部分通用逻辑
上述代码声明了T类型的Presenter, 根据BaseActivity的声明可以得知T类型就是我们需要的Presenter的实际类型.
在onCreate方法中, 首先通过getLayoutId()抽象方法来获取Activity的布局id, 然后通过setContentView()设置到content中. 这样我们在BaseActivity的子类中就无需再复写onCreate方法. 然后通过createPresenter()抽象方法来实例化声明的presenter. 由于presenter是protected, 因此子类可以直接使用presenter成员变量. 接着调用presenter的attachView()方法将View与Presenter绑定起来, attachView()的实现会在下面贴出来. 最后调用了抽象方法init(Bundle savedInstanceState), 来替代onCreate方法.
在onDestroy中, 首先通过presenter的detachView()将View与Presenter解绑, 同时将presenter置空, 很大程度上避免了内存泄漏的可能.
可以看到, BaseActivity为子类做了如下逻辑, 子类无需再做:
设置布局视图
声明以及初始化Presenter
将Presenter与View绑定
初始化Activity
将Presenter与View解除绑定
子类需要实现三个抽象方法, 具体含义请参考注释:
int getLayoutId()
T createPresenter()
void init(Bundle savedInstanceState)
BasePresenter部分通用逻辑
BasePresenter的逻辑比较简单, 就不做过多解释了, 同样的BasePresenter的子类可以直接使用view变量, 当然这里的view只是一个接口, 具体还需要BaseActivity子类去实现. 如果不去实现则会报类型转换错误. onViewAttached()方法通过名字也可以知道作用, 一些需要延迟初始化的变量或代码可以在覆写的onViewAttached()方法里写.
BaseView部分代码
BaseView接口中抽象了几乎所有页面都会使用的方法, 有了BaseView, 我们就可以利用BaseView为开发者做一些通用的逻辑, 比如自动隐藏加载框, 自动提示服务器返回的错误消息或者是网络错误消息等. 但是这段代码不在Presenter或View中, 以后会提及.
BaseActivty默认实现了BaseView, 因此BaseActivty的子类去实现BaseView的子类时, 只需要实现BaseView中没有的方法即可. 也可以通过覆写已实现的方法来达到细化控制的目的.
BaseActivity的完整声明
public abstract class BaseActivity<V extends BaseView, T extends BasePresenter<V>>
extends FragmentActivity implements BaseView
以上就是通过泛型来抽象通用逻辑的过程, 当然这三个Base类中还可以加入更多的逻辑, 这里只是其中一部分, 比如BaseActivity中还加入了ButterKnife的bind()方法, 以及加载框等.