MVP架构笔记之-DI框架dagger2

时间:2022-04-29 21:10:20

         dagger2在mvp架构开发中主要起到了解耦的作用,我的上一篇文章MVP架构笔记之初探--mvp原理写的是一个最为基础的MVP架构,其实啊,这个架构是耦合的一个架构,我们的view层持有一个MvpPresenter()对象实例;我们的P层构造函数里面又新建了一个m层的对象实例,这样view依赖presenter,presenter又依赖model就是一个紧耦合的架构。

          现在在我们用dagger2对上面的mvp架构进行改进,在这之前先对dagger2进行了解,首先dagger2的官网

https://google.github.io/dagger/    以及dagger2的github开源地址 https://github.com/google/dagger,dagger2几个新属性的价绍:

@Inject   可以注解成员变量和构造函数,如上面的view层持有的p的对象变量和p的构造函数
@Module 可用来注解无法由我们注解构造函数的第三方类、系统类、接口类,如retrofit,okhttp,gson等
@Provides 注解修饰的方法,一般用于@Module注解类中的方法,负责提供具体类型的依赖
@Componet
负责修饰接口或抽象类,提供inject抽象方法等待相应的页面oncreate时实现注入,提供
modules=xxmodule.class链接module,实现@Inject  和@Module中间链接桥的作用

还有一个非必需但很重要的,

@scope :作用域,dagger2给我们提供了一种@Singleton单例,其他的类型需要我们自己定义,比如@ApplicationScope@ActivityScope,@FragmentScope等,定义方式可以如下:

@Scope
@Retention(RUNTIME)
public @interface ActivityScope {}

需要了解更多scope原理请参考文档:http://www.cnblogs.com/tiantianbyconan/p/5095426.html

接下来,先来看一下我们改造过后的项目代码,首先我们看构造函数完成注入的方式activity中:

public class MainActivity extends AppCompatActivity implements MvpContract.View {

@Inject
TestPresenter presenter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DaggerMainActivityComponent.create().inject(this);
setContentView(R.layout.activity_main);
presenter.toString();
}

@Override
public void showData(String data) {
Toast.makeText(this, data, Toast.LENGTH_SHORT).show();
}

@Override
public void showload() {

}
}
public class TestPresenter {
String temp;

@Inject
public TestPresenter() {
temp = "测试数据";
}

public String toString() {
return temp;
}
}
@Component
public interface MainActivityComponent {
void inject(MainActivity activity);
}

为了测试方便,我新建了一个presenter,因为我在presenter中暂时还不想拿model和view对象,如上,我们发现activity的代码变得简单了许多,其中最关键的步骤就是我们开始注解的这一步

DaggerMainActivityComponent.create().inject(this);

这一步事真正实现presenter对象的实例化的,不然你可以把这行代码去掉,看你的presenter会不会报空指针异常,当然我们并没有写DaggerMainAcitivityComponent这类,这个类是我们的链接桥MainActivitiyComponent运行时生成的类,所以我们需要先把工程build一下才能调用这个类。注意:上述案例是在项目的mvpdagger2分支

接下来,我们来看一下当包含module时得实现方式,先看看我们得工程目录,我对代码进行了分包:

MVP架构笔记之-DI框架dagger2

相比于前一个案例,确实复杂了不少,但分得却很明确,framework包下主要定义一些抽象得接口和公用得东西;di包下主要定义了module和component,前面我们也定义了component 的;mvp下对主要功能进行分层,契约类、M层、P层和v层,整个架构的思想如下图:

MVP架构笔记之-DI框架dagger2

可以看到我们得契约类和先前得不太一样了,主要作用是对model和view层进行管理,即我们需要在presenter中处理的类对象,契约类如下:

public interface MainContract {
//对于经常使用的关于UI的方法可以定义到IView中,如显示隐藏进度条,和显示文字消息
interface View extends IView {
void showData(String string);
}

//Model层定义接口,外部只需关心Model返回的数据,无需关心内部细节,即是否使用缓存
interface Model extends IModel {
String getData();
}
}

接下来实现model层:

@ActivityScope
public class MainModel implements MainContract.Model {

@Inject
public MainModel() {
//获取网络数据或者缓存数据
}

@Override
public void onDestroy() {
}

@Override
public String getData() {
return "来自model层得数据";
}
}

可以看到我们对构造函数进行了注解,这里要写的原因是和我们module里面的写法有关系,如下:

@Module
public class MainModule {
private MainContract.View view;

/**
* 构建MainModule时,将View的实现类传进来,这样就可以提供View的实现类给presenter
*
* @param view
*/
public MainModule(MainContract.View view) {
this.view = view;
}

@ActivityScope
@Provides
MainContract.View provideMainView() {
return this.view;
}

@ActivityScope
@Provides
MainContract.Model provideMainModel(MainModel model) {
return model;
}

// @ActivityScope
// @Provides
// MainContract.Model provideMainModel() {
// return new MainModel();
// }
}

我们写的函数需要给函数提供值,所以注解了构造函数,当然如果换成下面不提供值,直接新建对象的话就不需要提供数据的来源了,自然也不需要@inject model 的构造函数;你可以跑一跑程序试试,两种是一样的效果。在如上两个类中我们都看到了有一个自定义注解@ActivityScope  ,表示只针对当前的Activity 有效,限制作用域范围,注解在类上表示类,注解在方法上表示方法,把modlue都写好了就该我们的连接器component登场了,如下:

@ActivityScope
@Component(modules = MainModule.class)
public interface MainComponent {
void inject(MainActivity activity);
}

这里是一个接口,暴露了抽象方法给外部,由MainModule提供数据,等着页面来注解,同样在activity里面进行数据的注入操作,如下:

@Inject
MainPresenter mainPresenter;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainComponent.builder()
.mainModule(new MainModule(this))
.build()
.inject(this);

mainPresenter.getData();
}
@Override    public void showData(String string) {        Log.e("yy", string);    }

至此,我们就完成了整个主流程的操作。还有一个默认的@scope操作符@Singleton我忘记介绍了,其实和@ActivityScope类似,可以修饰相应的类和方法,如下:

@Singleton
@Provides
MainContract.Model provideMainModel(MainModel model) {
return model;
}

表示单例model,最后运行一下我们的程序结果如下:

MVP架构笔记之-DI框架dagger2
代码在项目的mvpdagger2module分支,通过这两个案例我们对dagger2的使用有了一个初步的了解,其实dagger2还有更强大的用法,dagger.android,这个我也还没掌握。哈哈,大家可以看下引入规则,dagger2:

implementation 'com.google.dagger:dagger:2.14.1'
annotationProcessor 'com.google.dagger:dagger-compiler:2.14.1'

dagger2.android 需要内外添加:

implementation 'com.google.dagger:dagger-android:2.14.1'
implementation 'com.google.dagger:dagger-android-support:2.14.1'
// if you use the support libraries
annotationProcessor 'com.google.dagger:dagger-android-processor:2.14.1'

最后,给出代码的git地址:

https://github.com/yangyong915/MvpManager-yy

如果你觉得好,一定记得STAR哦。