Android

浅谈 MVP in Android

 https://www.jianshu.com/p/4736ebe1114b

鸿洋大神写的,MVP模式的基础介绍

传统MVP的弊端:

MVP需要创建太多的类和接口,并且每次通信都需要繁琐的通过接口传递信息

软解决,那就要动动脑子,稍微优雅的解决了

  1. 对于逻辑简单的页面可以不使用Presenter,直接在ActivityFragment中处理逻辑,在Presenter中如果不需要处理数据,也可以不使用Model

  2. PresenterModel都可以无限制的重用,所以MVP的划分不需要太细粒度,稍微粗粒度一点,即不需要每个ActivityFragment都给他划分一套MVP,可以几个ActivityFragment使用同一个Presenter(使用同一个类不是同一个对象,这个Presenter含有可以共用的逻辑),也可一个ActivityFragment根据不同的需求持有多个不同类型的Presenter对象,Model层同理,这样灵活使用,可以在一定程度上缓解MVP类和接口较多的缺点

通过上面的解决方案,是可以一定的缓解MVP的缺点,但是并不能完全解决上述缺点

比如想重用Presenter,Presenter就必须只含有公用的逻辑,而实际项目中公用的逻辑并不是那么多,所以能减少的类和接口也是很有限的,如果强制将不同页面的逻辑放在同一个Prsenter中,来达到重用的目的,那么每个Activity会被迫实现许多并不需要的方法,得不偿失

总结一下MVP的缺点:
1.粒度不好控制,控制不好就需要写过多的类和接口
2.如要重用presenter可能会实现过多不需要的接口
3.Presenter和View通过接口通信太繁琐,一旦View层需要的数据变化,那么对应的接口就需要更改

如何更高效的使用MVP以及官方MVP架构解析

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量的开源项目,所以对比了下我的框架,有以下几点:

  1. 使用Dagger的场景太少了,大部分只是使用Dagger注入MVP类,并且有些Retrofit都是自己new,并没有使用Dagger管理,甚至有些使用一次接口就retrofit.create(ApiService.class)一次,这个本可以使用Dagger将它作为单例来调用的

  2. 有一些设计的ComponentModule完全只是用来注入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最大的好处之一就是可以重用MP

  • 有些没有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

原文地址:https://www.cnblogs.com/qlky/p/7300517.html