https://www.jianshu.com/p/4736ebe1114b
鸿洋大神写的,MVP模式的基础介绍
传统MVP的弊端:
MVP需要创建太多的类和接口,并且每次通信都需要繁琐的通过接口传递信息
软解决,那就要动动脑子,稍微优雅的解决了
-
对于逻辑简单的页面可以不使用Presenter,直接在Activity或Fragment中处理逻辑,在Presenter中如果不需要处理数据,也可以不使用Model
-
Presenter和Model都可以无限制的重用,所以MVP的划分不需要太细粒度,稍微粗粒度一点,即不需要每个Activity或Fragment都给他划分一套MVP,可以几个Activity或Fragment使用同一个Presenter(使用同一个类不是同一个对象,这个Presenter含有可以共用的逻辑),也可一个Activity或Fragment根据不同的需求持有多个不同类型的Presenter对象,Model层同理,这样灵活使用,可以在一定程度上缓解MVP类和接口较多的缺点
通过上面的解决方案,是可以一定的缓解MVP的缺点,但是并不能完全解决上述缺点
比如想重用Presenter,Presenter就必须只含有公用的逻辑,而实际项目中公用的逻辑并不是那么多,所以能减少的类和接口也是很有限的,如果强制将不同页面的逻辑放在同一个Prsenter中,来达到重用的目的,那么每个Activity会被迫实现许多并不需要的方法,得不偿失
1.粒度不好控制,控制不好就需要写过多的类和接口
2.如要重用presenter可能会实现过多不需要的接口
3.Presenter和View通过接口通信太繁琐,一旦View层需要的数据变化,那么对应的接口就需要更改
presenter一直持有Activity对象导致的内存泄漏问题
写mvp的时候,presenter会持有view,如果presenter有后台异步的长时间的动作,比如网络请求,这时如果返回退出了Activity,后台异步的动作不会立即停止,这里就会有内存泄漏的隐患,所以会在presenter中加入一个销毁view的方法
BasePresenter
通用的presenter来为我们添加view的绑定与销毁
//presenter中添加mvpView 置为null的方法 public void onDestroy(){ mvpView = null; } //退出时销毁持有Activity @Override protected void onDestroy() { mvpPresenter.onDestroy(); super.onDestroy(); }
BaseView
界面需要提供的UI方法中会有很多类似的UI方法,可以把它们提取到一个公共的父类接口中。比如提取显示loading界面和隐藏loading界面的方法,其他的view层接口就可以直接继承BaseView接口,不必重复的写显示和隐藏loading界面方法。
BaseMvpActivity
presenter绑定到activity和View的绑定和解绑操作是每个Activity都会去做的,同样这里我也希望能有一个父类来完成这个统一的操作。
Dagger的用处
构建一个对象有时候还要构建一堆其他的对象,并且其他对象的构建同样复杂,并且必须按顺序构建,而且需要的对象的生命周期都不一样,有些生命周期可能和Activity一样,有些可能是单例,所以在构建的时候还要考虑对象声明周期,考虑对象的来源
这个时候依赖注入框架就派上用场了,我们只用专注于怎么实现功能,对象的依赖关系和生命周期,都让它来帮我们管理,一个Inject,它会按照依赖关系帮我们注入我们需要的对象,并且它会管理好每个对象的生命周期,在生命周期还没结束的情况下是不会重复new的
之前我看了几个使用MVP+Dagger+Retrofit开发,并且有一定star量的开源项目,所以对比了下我的框架,有以下几点:
-
使用Dagger的场景太少了,大部分只是使用Dagger注入MVP类,并且有些Retrofit都是自己new,并没有使用Dagger管理,甚至有些使用一次接口就retrofit.create(ApiService.class)一次,这个本可以使用Dagger将它作为单例来调用的
-
有一些设计的Component和Module完全只是用来注入Activity和一些单例
@ActivityScope @Component(modules = {ActivityModule.class},dependencies = {AppComponent.class}) public interface ActivityComponent { void inject(AActivity activity); void inject(BActivity activity); void inject(CActivity activity); ... }
-
还是和第2条有关,如果只有一个Module,
Dagger
就无法根据每个Presenter的需要,提供多个不同的Model,比如这个Presenter使用过这个接口,并且缓存已经在Model中写好,其他Presenter如果也要用到这个接口,就可以直接重用这个Model,MVP最大的好处之一就是可以重用M和P层 -
有些没有Model层,直接给Presenter注入Retrofit Api(有些是注入一个管理类,如果项目小接口少,这样还不错,但是有没有想过项目一大,接口一多里面就非常混乱),所有网络请求逻辑在Presenter中,如果现在需求变了,需要加入缓存,就需要更改Presenter的逻辑,这样就可能影响一些和这个功能无关的逻辑,如果有Model层,里面持有请求网络和缓存的功能类,这样Presenter就不需要管,数据是从网络还是数据库获取的,Model层只用保证返回给Presenter的数据无误,而Presenter只用专注于逻辑,这样各自只用保证各自的职责,屏蔽细节,易扩展,出错也好定位
Dagger注入MVP
Contract
这里根据Google
官方的MVP项目,可以在Contract中定义MVP的接口,便于管理,此框架无需定义Presenter接口,所以Contract只定义Model和View的接口
View
一般让 Activity 或 Fragment 实现 Contract 中定义的 View 接口,供 Presenter 调用对应方法操作 UI , BaseActivity 默认注入 Presenter ,如想使用 Presenter ,必须指定 Presenter 的范型(虽然只可以指定一个范型,但是可以自行生成并持有多个 Presenter ,达到重用的目的),和实现setupActivityComponent 来提供 Presenter 需要的 Component 和 Module(如这个页面逻辑简单并不需要 Presenter ,那就不指定范型,也不实现方法)
Model
Model 实现 Contract 的 Model 接口,并且继承 BaseModel ,然后通过 IRepositoryManager 拿到需要的 Service 和 Cache 为 Presenter 提供需要的数据(是否使用缓存请自行选择)
Presenter
Presenter在MVP中的大部分的作用为通过从Model层接口获取数据,在调用View层接口显示数据,首先实现BasePresenter,指定Model和View的范型,注意一定要指定Contract中定义的接口,Presenter需要的Model和View,都使用Dagger2注入,这样即解藕又方便测试,怎么注入?
MVP Module
这里的Module提供当前业务逻辑对应的View和Model接口(Contract中定义的接口)的实现类,Model需要AppComponent中提供的RepositoryManager来实现网络请求和缓存,所以需要通过Component依赖AppComponent来拿到这个对象
Dagger Scope
在上面的代码中 ActivityScope 大量出现在 Module 和 Component 中,Dagger2 使用 Scope 限制每个 Module 中提供的对象的生命周期, Dagger2 默认只提供一个 @Singleton
Scope 即单例,本框架提供 @ActvityScope 和 @FragmentScope ,如有其他需求请自行实现, Module 和 Component 定义相同的 Scope 后 Module 中提供的对象的生命周期会和 Component 的生命周期相绑定(即在 Component 生命周期内,如需多次使用到 Moudle 中提供的对象,但只会调用一次@Provide 注解的方法得到此对象)
Dagger注入单例
AppComponent
Application生命周期是和App是一样的,所以适合提供一些单例对象,本框架使用Dagger2
管理,使用AppComponent来提供全局所有的单例对象,所以需要自定义一个Application继承自BaseApplication,即可在App的任何地方,通过BaseApplication的getAppComponent()方法,拿到AppComponent里面声明的所有单例对象
RepositoryManager
RepositoryManager 用来管理网络请求层,以及数据库请求层
AppManager(管理所有的Activity)
AppManager用于管理所有的Activity,内部持有一个含有所有存活的Activity(未调用onDestroy)的List,和一个当前在最前端的Activity(未调用onPause),AppManager封装有多种方法,可以很方便的对它们进行操作,也可以在未持有AppManager的情况下,通过EventBus
远程遥控它的所有方法,这样我们可以在整个app的任何地方对任何Activity进行全局操作,比如在app请求网络超时时让最前端的Activity显示连接超时的交互页面(这个逻辑不用写到当前请求的Activity里,可以在一个单例类里做全局的统一操作,因为可以随时通过AppManager拿到当前的Activity)
在任意位置关闭所有的activity,获得在前台的activity做一些操作,判断某个activity实例是否存活
ActivityLifeCycle
Application继承activityLifeCycle管理生命周期
oncreate时:
activity加入appmanager
注入Dagger单例
onresume时:
设定当前的前台activity
onDestroy时:
移除所有的activity
Module
ClientModule:
提供retrofit,okhttp,database单例
AppModuel:
提供application,RepositoryManager单例
BaseActivity
设置mainContentView
绑定butterKnife
设定toolbar