mvp话说也出来很久了,初入学习Dagger的时候,就感觉和mvp结合能更加有效的解决presenter注入的的问题,避免更多的代码复写!而且大概看了下网络上的资源,一般多是分开讲解dagger和mvp技术,结合使用的很少,所以决定写出来和大家一起学习!
MVP,全称 Model-View-Presenter,要说MVP那就不得不说一说它的前辈MVC。
MVC(Model-View-Controller,模型-视图-控制器)模式是80年代Smalltalk-80出现的一种软件设计模式,后来得到了广泛的应用,其主要目的在于促进应用中模型,视图,控制器间的关注的清晰分离。MVP(Model-View-Presenter,模型-视图-表示器)模式则是由IBM开发出来的一个针对C++和Java的编程模型,大概出现于2000年,是MVC模式的一个变种,主要用来隔离UI、UI逻辑和业务逻辑、数据。也就是说,MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示,所有通信都是单向的;
MVP 模式将 Controller 改名为 Presenter,同时改变了通信方向
1. 各部分之间的通信,都是双向的。
2. View 与 Model 不发生联系,都通过 Presenter 传递。
3. View 非常薄,不部署任何业务逻辑,称为”被动视图”(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。
因此我们可以发现MVP的优点如下:
1、模型与视图完全分离,我们可以修改视图而不影响模型;
2、可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部;
3、我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁;
4、如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)。
具体到Android App中,一般可以将App根据程序的结构进行纵向划分,根据MVP可以将App分别为模型层(M),UI层(V)和逻辑层(P)。
UI层一般包括Activity,Fragment,Adapter等直接和UI相关的类,UI层的Activity在启动之后实例化相应的Presenter,App的控制权后移,由UI转移到Presenter,两者之间的通信通过BroadCast、Handler或者接口完成,只传递事件和结果。
举个简单的例子,UI层通知逻辑层(Presenter)用户点击了一个Button,逻辑层(Presenter)自己决定应该用什么行为进行响应,该找哪个模型(Model)去做这件事,最后逻辑层(Presenter)将完成的结果更新到UI层
如何把mvp实现在我们的代码上呢?
可以从上面简单的demo的结构上看出,model和ui层都是提供了一个外部接口类,而presenter拥有这两个类的依赖,而MvpActivity拥有presenter的依赖,当MvpActivity触发事件后通过presenter触发事件处理model,当model处理完成以后通过ui外部接口类回调给activity!
定义事件方法
public interface MvpUiImpl {
void showTest(String msg);
}
public class MvpActivity extends AppCompatActivity implements MvpUiImpl{
MvpPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mvp);
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
presenter.testDoS();
}
});
}
@Override
public void showTest(String msg) {
TextView tv=(TextView)findViewById(R.id.tv);
tv.setText(msg);
}
}
model接口定义处理数据方法
public interface MvpModelImpl {
MvpEntity test();
}
实现具体的数据处理方法
public class MvpModel implements MvpModelImpl{
@Override
public MvpEntity test() {
return new MvpEntity("数据");
}
}
通过ui和model对象的引用对象,事件触发后调用数据model处理方法,成功后回调给ui界面
public class MvpPresenter {
MvpUiImpl ui;
MvpModelImpl model;
public MvpPresenter(MvpUiImpl ui, MvpModelImpl model) {
this.ui = ui;
this.model = model;
}
public void testDoS() {
MvpEntity entity = model.test();
ui.showTest(entity.getMsg());
}
}
通过上面简单的构建,到这里一个传统的mvp构建就算是完成了!但是 MvpPresenter类初始化需要传递的两个依赖对象,这里正好我们可以使用dagger2的依赖注入实现MvpPresenter,减少程序的耦合度!
Dagger在mvp中的运用主要是优化Presenter创建依赖对象,所以开始我们的优化!
既然需要得到一个Presenter,首先需要构建一个对应的module
@PerApp
@Module
public class MvpPresenterModule {
private MvpActivity activity;
public MvpPresenterModule(MvpActivity activity) {
this.activity = activity;
}
@Provides
MvpActivity provideActivity(){
return activity;
}
@Provides
MvpPresenter providePresenter(MvpActivity ui,MvpModel mvpModel){
return new MvpPresenter(ui,mvpModel);
}
@Provides
MvpModel provideMvpModel(){
return new MvpModel();
}
}
注意:看完这段代码估计有同学发现,和之前的model构建好像不一样呀,对!这里我们在MvpPresenterModule 中首先提供了两个@Provides定义的方法,一个方法提供了MvpActivity ,另一个提供了一个MvpModel 对象;而这两个不正式初始MvpPresenter的依赖注入对象嘛!
是的这里我们通过dagger自带的@Provides方法,首先提供了两个MvpPresenter初始需要的对象,然后在@Provides定义一个MvpPresenter providePresenter(MvpActivity ui,MvpModel mvpModel)
方法,让Dagger自动为我们创建一个MvpPresenter 对象
和传统Dagger构建一样,Component定义依赖的model,inject定义消耗的activity对象
@PerApp
@Singleton
@Component(modules = MvpPresenterModule.class)
public interface MvpPresenterComponent {
void inject(MvpActivity activity);
}
public class MvpActivity extends AppCompatActivity implements MvpUiImpl{
@Inject
MvpPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mvp);
MvpPresenterComponent component= DaggerMvpPresenterComponent.builder().mvpPresenterModule(new MvpPresenterModule(this))
.build();
component.inject(this);
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
presenter.testDoS();
}
});
}
@Override
public void showTest(String msg) {
TextView tv=(TextView)findViewById(R.id.tv);
tv.setText(msg);
}
}
如有帮助欢迎start和留言!
传送门-Github
传送门-CSDN