解析Dagger中的Scope

本文适合学习使用过Dagger后,对Scope概念还感到困惑的朋友,文中不会介绍Dagger的基本知识。

Dagger是一个优秀的依赖注入框架,使用它会大大降低项目各模块间的耦合,提高项目的可扩展性。我看到简书上讲Dagger的文章不少,但大都对其Scope概念语焉不详,显然作者本人也没有完全搞清楚。于是我决定写篇小文来解释一下Scope的含义及用法。

一、不同组件有不同的用途

使用Dagger,需要定义很多组件,不同的组件是为了完成不同的依赖注入功能。比如,有的组件是为了给某个Activity注入依赖,有的是为了给某个Service注入依赖。从组件里面的inject方法可以了解这个组件是给谁注入依赖的。举例如下:

//这个组件是用来给MainActivity注入依赖的
@Component(modules ={MainModule.class})
public interface MainComponent {
  void inject(MainActivity activity);
}

//这个组件是用来给MainService注入依赖的
@Component(modules ={BackModule.class})
public interface BackComponent {
  void inject(MainService service);
}

二、让MainComponent与MainActivity的生命周期保持同步

MainComponent用来给MainActivity注入依赖,我们当然希望MainComponent与MainActivity“同生共死”,即MainActivity创建的同时创建MainComponent,MainActivity销毁的同时销毁MainComponent。

那么怎么做到呢?

1、定义Scope

我们可以定义一个Scope注解,把它加到MainComponent头上。

定义Scope如下:

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface MainActivityScope {

}

2、为MainComponent添加Scope

现在,我们把上面自定义的Scope添加到MainComponent头上,如下:

//这个组件是用来给MainActivity注入依赖的
@MainActivityScope
@Component(modules ={MainModule.class})
public interface MainComponent {
  void inject(MainActivity activity);
}

3、将MainComponent与MainActivity同步

很多初学者,误以为添加上自定义的Scope后,MainComponent就会获得一种神奇的能力,能够自动实现与MainActivity的“生死与共”。这种想法天真烂漫可爱,但却是错误的。

添加上自定义的Scope后,MainComponent并没有获得什么超能力,要想让它与MainActivity的生命周期同步,还需要我们手动完成,即:

  • MainActivity的onCreate方法中创建MainComponent并完成依赖注入
  • MainActivity的onDestroy方法中销毁MainComponent

三、Scope为我们带来的好处

有的人说,既然Scope根本无法决定MainComponent的创建销毁,最终还要靠我们手动完成,那我为什么要使用Scope?

原因有三。

1、方便管理

在MainComponent加上@MainActivityScope注解后,我们可以很清楚地知道,这个组件是用来给MainActivity注入依赖的,这会提醒我们将MainComponent的创建销毁与MainActivity关联起来。

2、不得不用

Dagger可以使用组件依赖,将不同的组件组合起来完成某个依赖注入任务,但它规定:父组件与子组件不能有相同的Scope,这时候就不得不自己定义Scope。

3、实现单例

这是我认为最重要的一点。还是以上面的MainComponent为例,它有一个模块,即MainModule,假设它包含如下内容:

@Module
public class MainModule {
    Application mApp;
    public MainModule(Application app){
        this.mApp = app ;
    }
    @Provides
    Application providesApplication(){
              return mApp ;
    }
    @Provides
    OkHttpClient providesOkHttpClient(){
          return new OkHttpClient();
    }

Dagger规定,一个组件的模块中的@Provides注解的方法,要不加上与组件相同的Scope,要不就不加。在我们的例子中,MainModule的两个被@Provides注解的方法都没有加@MainActivityScope注解。我们来看看这会造成什么后果。

第一个方法提供Application实例,它直接返回模块MainModule内缓存的Application实例,由此我们知道,组件MainComponent提供的Application实例只有一个,就是模块MainModule创建时传入的Application实例,这时我们说,MainComponent注入的Application实例是一个单例

第二个方法提供OkHttpClient实例,在 providesOkHttpClient方法中,会new一个OkHtttpClient实例返回。这意味着,每当我们用MainComponent注入OkHttpClient实例时,都会重新创建一个崭新的OkHttpClient实例,如果你注入五次,那么就会有五个OkHttpClient实例。

这显然不是我们想要的结果,我们希望用MainComponent注入的OkHttpClient也是单例,怎么办?
我们可以给providesOkHttpClient方法加上@MainActivityScope注解,如下:

 @Provides
 @MainActivityScope
    OkHttpClient providesOkHttpClient(){
          return new OkHttpClient();
    }

有了这个注解,当我们第一次用MainComponent注入OkHttpClient实例时,Dagger会调用providesOkHttpClient方法创建一个OkHttpClient实例返回,同时,Dagger会缓存这个新创建的实例。

以后,只要这个MainComponent没有销毁,再次使用MainComponent注入OkHttpClient实例时,Dagger都会直接返回缓存的OkHttpClient实例,而不是调用providesOkHttpClient方法创建新的OkHttpClient实例。这就确保了MainComponent注入的依赖都是一个实例,也就是实现了单例模式。

好了,希望你读完本文能够帮助你理解掌握Dagger中的Scope概念,在工作中更好地使用Dagger。

    原文作者:milter
    原文地址: https://www.jianshu.com/p/c4ed826c1473
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞