更清晰的Dagger2

作者: 编程应用  发布:2019-09-06

在轻便利用了一段时间的dagger2之后,来谈谈对dagger2浅薄的认识。

Dagger2 与 MVP

Dagger2是Google提供的倚重注入框架,正视注入为Android中组件之间的解耦提供了很好的应用方案。Dagger2已经在更增多的开源项目中被利用,其已经前进产生未来的一个技艺可行性。
MVP设计形式大家也十分熟识,其定义不在此处赘述。MVP的贯彻方式丰裕七种,和Dagger2相结合专门的工作本文要阐释和探讨的。

MVP形式将原来二个Activity能够缓和的主题素材,分成了M、V、P三有的,那在项目中会产品多量的类,借使使用Dagger2来实行这个类的立竿见影管理,是本文思虑的主题材料。本文将从Dagger2基础论述,MVP的落到实处际意况势以及Dagger2和MVP的整合,七个地点来谈谈,希望对我们有用。

首先,使用依赖注入能够带来什么好处?

Dagger2 基础

Dagger2首要基于评释来促成,刚接触Dagger2的时候都会有这么的吸引:

  • Inject,Component,Module,Provides,Scope,Qualifier是如何鬼?
  • Dagger2如何使用到花色中?

Inject
Inject,即注入,该评释标示地点代表需求经过DI框架来注入实例。Inject有二种办法,分别是Constructor injection、Fields injection、Methods injection。表明了Inject之后,会从注入框架中去搜寻供给注入的类实例,然后注入进来,相当于透过Component去寻找。这两种注入的表现情势如下:

public class SolutionCreatePresenterImpl implements SolutionCreatePresenter {
...
  @Inject
  public SolutionCreatePresenterImpl(Activity activity, StudioApiService apiService, RxBus rxBus, DataCenter dataCenter) {
  this.activity = activity;
   this.apiService = apiService;
   this.rxBus = rxBus;
   ...
 }
}

public class SolutionCreateActivity extends BasePresenterActivity implements SolutionCreateView {

 @Inject
 SolutionCreatePresenter solutionCreatePresenter;
 @Inject
 RxBus rxBus;
 @Inject
 DataCenter dataCenter;

 @Overrideprotected void onCreate(@Nullable Bundle savedInstanceState  {
  super.onCreate(savedInstanceState);
  component().inject(this);
  ...
 }

}

public class LoginActivityPresenter { 
  private LoginActivity loginActivity; 

  @Inject
  public LoginActivityPresenter(LoginActivity loginActivity) {
    this.loginActivity = loginActivity;
  }

  @Inject
  public void enableWatches(Watches watches) {
    watches.register(this);  //Watches instance required fully constructed LoginActivityPresenter
  }
}

Component
Component 要消除的标题正是Inject的实例从哪个地方来,所以它承受的正是三个连接器的法力。Component须要引用到指标类的实例,Component会查找指标类中用Inject评释评释的习性,查找到相应的属性后会接着查找该属性对应的用Inject评释的构造函数(那时候就发生关联了),剩下的做事正是初阶化该属性的实例并把实例实行赋值。

Module
Module 是类实例提供的工厂方式,Module里面包车型大巴法门基本都是创办类实例的措施。那样,Dagger第22中学就有2个维度能够创设类实例:

  • 经过用Inject注明标记的构造函数来创制(以下简称Inject维度)
  • 因而工厂方式的Module来创制(以下简称Module维度)

Provides
Provides 用在Module中,注明方法能够回去dependencies,也等于格局能够提供被注入的类实例。

@Module
public class NetApiModule {

  @Provides
  @Singleton
  StudioApiService provideStudioApiService(RestApi restApi) {
    return restApi.retrofitStudio(GlobalConfig.STUDIO_API_BASE_URL).create(StudioApiService.class);
  }

  @Provides
  @Singleton
  RxBus provideRxBus() {
    return RxBus.getInstance();
  }
}

正如所以,NetApiModule提供了StudioAPIService、ENVISIONxBus类的依赖实例。

Scope
Dagger第22中学Scope关注的难题正是类实例的生命周期,@ApplicationScope 是愿意类实例和Application一样,相当于独一单例;@ActivityScope则指望类实例和Activity生命周期一致。如此,Scope就有“local singletons” 的定义了。例如:AppComponent 用 @Singleton 举行标记,由于AppComponent只在Application中开创一次,那就保险了AppComponent所引用的ApplicationModule 中用 @Singleton 标志的类都是单例;同样的,ActivityComponent 用 @ActivityScope举办标志,每一遍创造新的Activity都会创造七个ActivityComponent,那正是的ActivityComponent所引用的ActivityModule中用@ActivityScope 标志的类都富有和Activity一样的生命周期。
在背后的上书中,读者可以去体会Scope标志后的,类实例和Component的互相正视关系。

Qualifier
假使类实例创造有各类一模二样的终南捷径,就需求经过标签tag来区别之,并在注入的时候经过标签来分别。

Dagger2如何利用到品种中
Dagger2的利用首先要脱身古板的类创建方式,即废弃各样new的运用方法,要有类酒店的定义,全部类的援用选拔Inject来注入。其次,要组织好Component,Component是连接器,提供了分化的类注入,有为Application提供的,有为Activity提供的,遵照个人经历来说,Component的撤销合并有须臾间准绳:

  • 要有全局Component, 肩负管理整个app的全局类实例, 这几个类为主都是单例格局,一般都用@Singleton标志
  • 种种页面前蒙受应叁个Component,即每一种Activity 和 Fragment,谷歌(Google)官方Dagger2示例是使用这种方法,这种方法有个不佳地点,Component太多
  • 将页面重视的类抽取,公用贰个Component,有异乎经常需求的时候继承该公有Component
  • 分裂类别的Component及Module,选取Scope实行区分

参照他事他说加以考察链接:
Miroslaw Stanek: http://frogermcs.github.io/dependency-injection-with-dagger-2-the-api/
Google: https://github.com/google/dagger

1、重视的流入和布署独立于组件之外,注入的指标在三个独立、不耦合的地点发轫化,那样在改造注入对象时,我们只需求修改对象的达成情势,而不用大改代码库。

MVP 达成钻探

MVP的兑现方式相当多,这里介绍二种:

  1. 以Activity和Fragment作为View(视图层),Presenter管理业务逻辑;
  2. 运用Activity和Fragment作为presenters,View单独抽取处理视图相关。

使用Activity和Fragment作为View

这种方法是比较古板的贯彻情势,也正如相符大家的习于旧贯,因为事先都以在Activity里面管理View相关,改用MVP格局也只是也Activity里面包车型客车事情逻辑分红Presenter。这里要提的是谷歌官方MVP也是选拔这种艺术。
下边说一下小编的兑现情势,将Presenter和View都抽取贰个基类接口,每种Activity和Fragment都分别定义对应的Presenter和View接口,并集成基类接口。具体贯彻如下:

基类接口View

public interface LoadDataView {
  /**
  * Show a view with a progress_upload bar indicating a loading process.
  */
  void showLoading();

  /**
  * Hide a loading view.
  */
  void hideLoading();

  /**
  * Show a retry view in case of an error when retrieving data.
  */
  void showRetry();

  /**
  * Hide a retry view shown if there was an error when retrieving data.
  */
  void hideRetry();

  /**
  * Show an error message
  *
  * @param message A string representing an error.
  */
  void showError(String message);

  /**
  * Get a {@link Context}.
  */
  Context context();
}

基类接口Presenter

public interface Presenter<T> {
  /**
  * Method that control the lifecycle of the view. It should be called in the view's
  * (Activity or Fragment) onStart() method.
  */
  void start();

  /**
  * Method that control the lifecycle of the view. It should be called in the view's
  * (Activity or Fragment) onDestroy() method.
  */
  void destroy();

  void setView(T view);
}

大家以本文以前运用的SolutionCreatePresenter来陈说具体页面包车型大巴Presenter定义。

// 接口定义
public interface SolutionCreatePresenter extends
    Presenter<SolutionCreateView>, View.OnClickListener, View.OnFocusChangeListener {
  Solution getSolution();
  void setSolution(Solution solution);
}

// 接口实现
public class SolutionCreatePresenterImpl implements SolutionCreatePresenter {
 ...
  @Inject
  public SolutionCreatePresenterImpl(Activity activity, StudioApiService apiService, RxBus rxBus, DataCenter dataCenter) {
    this.activity = activity;
    this.apiService = apiService;
    this.rxBus = rxBus;
    ...
  }

  @Override
  public void setView(SolutionCreateView view) {
   this.solutionCreateView = view;
  }

  // 继续添加其他 override 方法
}

SolutionCreateActivity 见本文前边的代码,须求implements SoluionCreateView, 并且Inject SolutionPresenter.

使用Activity和Fragment作为Presenters
为什么要接纳这种格局呢,基于两点来设想:

  1. Activity Fragment本人就有生命周期的军管,这种管理类似于业务逻辑,所以要归为Presenter;
  2. Activity Fragment生命周期变化时,会带来业务逻辑的扭转,直接当做Presenter,能够幸免业务逻辑的纷纭。

当中意味,读者本人经验体验,当本身有要求时,能够根据那三种艺术随机转移。

参照链接:
一种在android中贯彻MVP格局的新思路:
https://github.com/hehonghui/android-tech-frontier/tree/master/androidweekly/一种在android中完结MVP格局的新思路
Google Samples:
https://github.com/googlesamples/android-architecture

2、重视能够注入到三个零件中:大家得以注入这一个依赖的模仿完成,那样使得测量试验特别简约。

Dagger2 与 MVP 的结合

这一有的,爱慕介绍Component 和 Module的安插性,目的在于更加好适应MVP方式。
基本思路:

  1. 全局Component通过AppComponent举办政管理理,许多设置单例情势;
  2. 将Activity和Fragment Component中通用的收取,为BaseViewComponent;
  3. 上层PresenterComponent承继BaseViewComponet,DataBandingComponent只好承接android.databinding.DataBindingComponent,但足以将BaseViewModule 满含进来。其余Component使用时方可持续BaseViewComponent。

架构图如下:

图片 1

dagger-mvp.jpeg

大旨代码如下:

AppComponent

@Singleton
@Component(modules = {AppModule.class, AppManageModule.class})
public interface AppComponent {
  void inject(DajiaApplication app);
}

AppModule

@Module(includes = NetApiModule.class)
public class AppModule {
  private final Application application;

  public AppModule(Application app) {
    application = app;
  }

  @Provides
  @Singleton
  Application provideApplication() {
    return application;
  }

  @Provides
  @Singleton
  Context provideContext() {
    return application;
  }
}

BaseViewComponent

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

@PerView
@Component(dependencies = AppComponent.class, modules = BaseViewModule.class)
public interface BaseViewComponent {

  Activity activity();

  void inject(AbstractActivity activity);

  void inject(BaseFragment fragment);
}

BaseViewModule

@Module
public class BaseViewModule {

  private final Activity activity;

  public BaseViewModule(Activity activity) {
    this.activity = activity;
  }

  @Provides
  @PerView
  Activity provideActivity() {
    return this.activity;
  }
}

PresenterComponent

@PerView
@Component(dependencies = AppComponent.class, modules = {
    BaseViewModule.class, PresenterModule.class
})
public interface PresenterComponent extends BaseViewComponent {
 void inject(SolutionCreateActivity activity);
}

PresenterModule

@Module
public class PresenterModule {
 @Provides
  @PerView
  SolutionCreatePresenter provideSolutionCreatePresenter(SolutionCreatePresenterImpl presenter) {
    return presenter;
  }
}

其余,能够将Activity和Fragment中公用的事物抽出AbstractActivity、BaseActivity、BasePresenterActiviy以及BaseFragment,并在这几个类中初阶化对应的Component。以AbstractActivity 和 BasePresenterActiviy为例:

public class AbstractActivity extends AppCompatActivity {

  private BaseViewComponent mBaseViewComponent;

  public BaseViewComponent component() {
    if (mBaseViewComponent == null) {
      mBaseViewComponent = DaggerBaseViewComponent.builder()
          .appComponent(DajiaApplication.getInstance().component())
          .baseViewModule(new BaseViewModule(this))
          .build();
    }
    return mBaseViewComponent;
  }

}

public class BasePresenterActivity extends BaseActivity {

  private PresenterComponent presenterComponent;

  public PresenterComponent component() {
    if (presenterComponent == null) {
      presenterComponent = DaggerPresenterComponent.builder()
          .appComponent(DajiaApplication.getInstance().component())
          .baseViewModule(new BaseViewModule(this))
          .presenterModule(new PresenterModule()).build();
    }
    return presenterComponent;
  }
}

诸有此类,在使用MVP时,服从如下步骤:

  1. 成立新的Presenter 承继 BasePresenter;
  2. 达成该接口,PresenterImpl;
  3. 在PresenterModule中提供PresenterImpl的注入方法;
  4. 创设新的View,承继BaseView;
  5. 创制新的页面Activity只怕Frament,implements View;
  6. PresenterComponent增多inject方法,在新的页面中inject Presenter。

3、app中的组件无需掌握关于实例创造和生命周期的另外事情,那个由大家的依赖注入框架处理的。

结语

本文想要系统的描述Dagger2和MVP的架构观念,可是文笔有限,行文中仍旧感觉有为数十分的多描述不做到的地方,希望读者在读书时把握主题情想,而不囿于于具体的贯彻步骤。

作者以为,dagger2那样的依附注入框架对MVP架构来讲,是最佳的解耦工具,能够更上一层楼下降modle-view-presenter之间的耦合度。所以,若是你的类型在采纳MVP架构开荒,刚强提出合营dagger2一同行使。

接下去,在贴代码此前,笔者先说表明下小编的MVP架商谈理念的MVP有些分裂,守旧MVP的M层处管事人务逻辑,P层仅仅是V和M的大桥;而自个儿的P层同不经常候管理与model相关的业务逻辑,不处理View等级次序的逻辑,View档期的顺序的逻辑交给V本人管理,M层仅仅是bean,这种措施是依据开荒中的实情而作的思考,这里先不作钻探。

先看结构图:

图片 2

接下去,分解那张图:AppComponent: 生命周期跟Application同样的零件。可注入到自定义的Application类中,@Singletion代表相继注入对象为单例。

@Singleton@Component(modules = AppModule.class)public interface AppComponent { Context context(); // 提供Applicaiton的Context ThreadExecutor threadExecutor(); // 线程池 ApiService apiService(); // 所有Api请求的管理类 SpfManager spfManager(); // SharedPreference管理类 DBManager dbManager(); // 数据库管理类}

AppModule: 这里提供了AppComponent里的要求注入的对象。

@Modulepublic class AppModule { private final MyApplication application; public AppModule(MyApplication application) { this.application = application; } @Provides @Singleton Context provideApplicationContext() { return application; } @Provides @Singleton ThreadExecutor provideThreadExecutor(JobExecutor jobExecutor) { return jobExecutor; } @Provides @Singleton ApiService providesApiService(RetrofitManager retrofitManager) { return retrofitManager.getService(); } @Provides @Singleton SpfManager provideSpfManager() { return new SpfManager(application); } @Provides @Singleton DBManager provideDBManager() { return new DBManager(application); }}

此地留意的童鞋恐怕开掘,为什么有些措施直接回到入参,有个别供给重返一个new的对象啊?这里若是对DBManager的写法换到:

DBManager provideDBManager(DBManager dbManager) { return dbManager;}

那般编写翻译不会由此,会报三个循环正视的失实,这种写法必要在回去参数和入参是三翻五次关系才方可。感兴趣的可以查阅dagger2生成的代码。

对于间接再次来到的类JobExecutor、RetrofitManager,它们类的构造函数必须要加上@Inject的解说:

@Injectpublic JobExecutor() { // 初始化 // ......}

接下去谈谈ActivityComponent,能够看看有个@ActivityScope注解,那么些注脚是自定义的,对应Activity的生命周期,Dagger2能够透过自定义证明限定申明作用域。

@Scope@Retentionpublic @interface ActivityScope {}

ActivityComponent:生命周期跟Activity同样的零部件,这里提供了inject方法将Activity注入到ActivityComponent中,通过该办法,将Activity中须要注入的靶子注入到该Activity中。

@ActivityScope@Component(dependencies = AppComponent.class, modules = ActivityModule.class)public interface ActivityComponent { Activity activity(); void inject(LoginActivity loginActivity); void inject(MainActivity mainActivity); // ....}

ActivityModule:注入Activity,同不时候明确Activity所对应的域是@ActivityScope

@Modulepublic class ActivityModule { private final Activity activity; public ActivityModule(Activity activity) { this.activity = activity; } @Provides @ActivityScope Activity activity() { return this.activity; }}

从那之后,注入职业启幕完毕了,看到这里,也许有童鞋有问号,Presenter的流入在何地,为啥没在ActivityComponent里?是的,不奇怪的话,结构图应该是上面那张图的圭表:

图片 3

自个儿建议采用这种格局,对于区别的Activity,创设各类对应的ActivityCompontent,相同的时候把Presenter注入到Component的视图中,这也是dagger2推荐的做法,Dagger 2希望采用@Component评释接口将借助关系链接起来。

而小编的做法未有把Presenter注入到ActivityComponent中,因为Presenter的成效域和Activity同样,好处是省去代码,大家能够依附项目情形自行采纳注入格局。

使用:

public class LoginActivity extends BaseActivity implements LoginView, ValidCodeView { @Inject LoginPresenter loginPresenter; @Inject ValidCodePresenter validCodePresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); initInject(); // 此处省略N行代码 } private void initInject() { // 构建Component并注入 getActivityComponent().inject; loginPresenter.attachView; validCodePresenter.attachView; } // 建议写在基类Activity里 protect ActivityComponent getActivityComponent(){ return DaggerActivityComponent.builder() .appComponent(getAppComponent .activityModule(getActivityModule .build(); } // 建议写在基类Activity里 protect ActivityModule getActivityModule(){ return new ActivityModule; } // 建议写在MyApplication类里 public AppComponent getAppComponent(){ return DaggerAppComponent.builder() .appModule(new AppModule((MyApplication)getApplicationContext .build(); }}

其中LoginPresenter:

@ActivityScopepublic class LoginPresenter extends DefaultMvpPresenter<LoginView, RESTResult<UserVO>> { // 此处省略 @Inject public LoginPresenter(ApiService apiService, ThreadExecutor jobExecutor, SpfManager spfManager) { this.apiService = apiService; this.jobExecutor = jobExecutor; this.spfManager = spfManager; } public void login(String mobile, String code) { // todo }}

那般,dagger2的轻巧利用就介绍完成了,如果有对有的基础概念不是很掌握的童鞋,能够查阅官方文书档案。

本文由今晚开什么码发布于编程应用,转载请注明出处:更清晰的Dagger2

关键词:

上一篇:没有了
下一篇:没有了