Dagger2 独家解读

2021-09-24  本文已影响0人  kevin910

1、Dagger2是干嘛的?

 Dagger2是用于依赖解耦的

2、要了解Dagger2他是怎么解耦的?

他是靠注解生成器,通过各种注解比如:@Component 、@Module、@Provides、@Named、@Singleton 等等

在AS  Build阶段,使用 com.google.dagger:dagger-compiler:2.11 注解生成器,按照已经实现好的代码,对我们项目的整个代码进行扫描注解,然后获取到带有相应注解的类,然后对带有注解的类重新生成一份代码

3、那么这个代码怎么生成呢?

javapoet  就是这个代码生成工具,这个工具应该算是和注解生成器一起使用的工具了,就是这个在生成各种我们需要的源代码。

那么生成的代码分为哪几种呢?

a、Dagger***Component  implements ***Component                Dagger的中间桥梁  实现自我们写的 ***Component(这下应该知道为啥                                                                                                                Component都是接口了吧)  例如:DaggerAppComponent implements                                                                                                         AppComponent

b、***Module_Provide***Factory                                                  Dagger创建实例方式一(通过添加了@Module的类),前面的*表示哪个                                                                                                         Module,后面的*代表生成的哪个实例 例如   :                                                                                                                                                 HttpModule_ProvideOkHttpBuilderFactory

c、***_Factory                                                                                Dagger创建实例方式二(通过在构造函数上添加@Inject),*表示了创建                                                                                                         的实例是哪个类的

d、***_MembersInjector                                                                Component添加的 注入类 即在我们自己创建的Component里面得 返回值                                                                                                           为void 的方法 例如:void inject(MainActivity activity);

生成的代码大致就是这几类

其中 a属于中间件,连接b、c  与 d的

b、c属于实例创建

d 属于实例获取  那么如果想要获取实例,只需要在对应的类中 初始化Dagger***Component的注入方法(该方法需要在自己写的***Component中自己写出来  例如:void inject(MainActivity activity);),然后在类里面使用@Inject即可

完整的如:

@Component( modules = ActivityModule.class)

public interface ActivityComponent {

void inject(MainActivity activity);

public class  MainActivity extends AppCompatActivity{

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    this.setContentView(this.getLayout());

    DaggerActivityComponent.builder()

    .build().inject(this)

    }

}

4、当我们使用@Inject 获取实例时,为啥不能获取类型相同的实例?

我觉得这个就好比,同一个对象不能创建 参数类型相同的构造函数一样。

那么如何解决这个问题呢?

1、在@Module的类的方法上添加 @Named("one") 注解 进行区分

2、使用@Qualifier注解 ,创建一个注解,并使用@Qualifier 对其注解   比如 @One   将这个注解添加在 @Provides 的方法上

例如:

@Qualifier

@Documented

@Retention(RUNTIME)

public @interface One{

}

在使用时,在@Inject注解上面添加 @One  即可获取到对应的实例

上述两种方法就好比:我们创建相同参数的构造函数时,添加一个type参数,用于区分不同的对象

5、为什么我使用@Singleton 注解时,在不同的Activity使用时,是不相同的单例对象?

在Dagger2看来  @Singleton 是属于Application单例还是Activity单例呢? 其实这个和Component的创建和销毁有关,如果在Application创建和销毁那么他就是进程级别的全局单例,如果是Activity创建和销毁的,那么他就是页面级别局部单例。

还记得我们要在某一个Activity使用Dagger2吗?  是不是需要先初始化,然后再使用? 虽然我们看不到销毁,但是当页面关闭掉后,GC会自动帮我们销毁掉,所以我们在Activity使用的基本都是页面级别的局部单例。

6、我们怎么创建全局单例呢?

Dagger2也想到了这个问题,那么 Component也就出现了一个继承的关系,还有 一个SubComponent的概念。即 父Component的全局范围一定要大于子Component,我们可以写一个AppComponent (父)和 ActivityComponent(子) AppComponent在Application中创建(所有需要全局单里的对象写在该Component的Module类里面即可),ActivityComponent在具体的Activity(所有Activity要使用的对象写在该Component的Module类里面即可)页面创建即可。

在此期间,我们可以使用@Scope注解 来添加新的注解  比如 @ActivityScope  用于标记我们子Component,这个@ActivityScope是标记我们的作用域,其实用处就是告知父Component  你的子Component的作用域小于你

注意:ActivityComponent创建时,记得传入全局的Appcomponent 这样我们就可以使用全局的单例对象了

总结:

自此Dagger2的解读就到这里,其实Dagger2一直围绕的都是 创建对象-使用对象这个主线来操作的。 因为他的核心是解耦,那么他必须要有一个中间件,将创建与使用对象结合起来,那么 中间件一定要能生成对象  也一定要能将对象注入到具体的类中,而且中间件也必须是独立的。

实现了中间件功能之后,就得要扩展,比如要是有多个相同的对象不同内容的实例怎么解决,要是有多个不同的页面怎么注入,要是想注入到不同页面的对象都是单例的怎么解决? 要是想复用其他中间件的实例怎么解决?

为什么要这些扩展? 因为不扩展就没有商用的价值,后面还有java向的扩展,android向的扩展。那么Dagger2也有对应的依赖,我想基于基本功能已经实现,那么偏向android的扩展应该是如何简化使用的吧,或者更加细粒度的功能。对于这些,如果不是真正的要完全使用他的话,基本看到这里就已经足够我们使用了。

上一篇下一篇

猜你喜欢

热点阅读