Dagger2进阶-范围的控制(Scope和Singleton)

前言

        Dagger2的介绍和配置

        Dagger2基础的使用

        Dagger2进阶-编译生成源码解读

        Dagger2进阶-范围的控制(Scope和Singleton)

        Dagger2进阶-Scope的源码探究

        项目源代码传送门

注解解释

    @Singleton:确定生成的类为单列,也就是确定对象的活动时间,属于全局单例,作用在使用@Provides方法上,也要配置到@Component中。

    @Scope:范围,在Dagger2中应用就是确定对象的生命周期,也就是确定对象的存活范围。是一个局部变量的注释,其活动范围在注释修饰的@Component内。

使用Singleton创建一个全局单例

我们的需求变成需要一个单列的对象的时候,我们如何做呢?

    我们先来看看没有做任何范围限定的范围操作的时候,是怎样的:


可以看到 两个Goods的地址引用是不一致的,说明对象的创建默认不是单列的,我们修改一下代码,商品类Goods由@Module提供并使用@Singleton修改,@Singleton修饰了@Provides提供的方法后,也要修改Component:


运行后,结果如下:


我们能看到,对象实现了单例了,@Singleton注解为生成了一个单例的对象,然而,真的是这样子吗?

我们建一下第二个Activity,然后新建一个新的组件,TwoComponent:



运行。。。 期待中  


然鹅,oh  my god 不是说好的单例吗,怎么引用地址变了。我们看看@Singleton的源码:

@Scope
@Documented
@Retention(RUNTIME)
public @interface Singleton {}

源码中我们知道@Singleton是使用了@Scopen的注释,其原理跟@Scope一样,所以其不是完全单例的,其确定的范围只是限定在其组件呢?后来我们会通过源码分析为什么会这样,接下来我们重头开始实现一个全应用的单例对象:

建立一个APP级别的Moduele和Component:

@Module
public class AppModule {

    @Singleton
    @Provides
    Goods providesGoods(){
        return new Goods();
    }
}
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    void inject(MyApplication myApplication);
    
    //告诉依赖的Component,我给你提供了这个类。比不可少。
    Goods getGoods();
}

然后我们下面进行修改Activity的组件:

@ActivityScope
@Component(modules = ObjectModule.class,dependencies = AppComponent.class)
public interface MainActivityComponet {

    void inject(MainActivity activity);
}
@ActivityScope
@Component(modules = ObjectModule.class,dependencies = AppComponent.class)
public interface TwoComponent {
    void inject(TwoActivity twoActivity);
}

两个都是使用dependencies 依赖一个父组件,并且设置一个@ActivityScope范围注解,不设置注解会报错,

@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {
}


因为需要依赖了组件,在MainActivity和TwoActivity中我们要告诉框架我们依赖的组件是什么



编译结果:



妥妥的全局单例完成。

使用@Scope创建一个局部单例

我想这个就不用我贴代码了。。其实@Singleton也是一个@Scope注解,只是框架给我们设定了一个而已,所以将@Singleton改成@ActivityScope我们就不会在错误的理解下建造一个局部单例。至于为什么范围是基于组件的范围的,我们可以这样理解,每个组件都是一个对象池,@Scope只是保持其在单个对象池唯一而已,具体源码分析会在后面更新。


常见问题:

1.当方法@Provides确定了Scoped时,组件Component没有设置Scoped:Error:(17, 1) 错误: com.lyc.love.dagger2demo.dagger2.component.MainActivityComponet (unscoped) may not reference scoped bindings:@[email protected] com.lyc.love.dagger2demo.dagger2.module.ObjectModule.provideGson()

2. 需要为依赖了用@Singleton修饰的组件,也提供一个@Scope:Error:(17, 1) 错误: This @Singleton component cannot depend on scoped components:

@Singleton com.lyc.love.dagger2demo.dagger2.component.AppComponent

3.Error:(18, 10) 错误: com.lyc.love.dagger2demo.bean.Goods cannot be provided without an @Inject constructor or 

这个错误有以下原因:

    @1、如果是依赖的Component提供的类,查询Component的Module是否有@Provided修饰。

    @2、如果是依赖的Component提供的类不存在上面的情况查询是否在Component向外提供了一个方法。比如:

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    void inject(MyApplication myApplication);

    //告诉依赖的Component,我给你提供了这个类。比不可少。
    Goods getGoods();
}

    @3.查看需要类的中的Module.是否修饰@Provided




猜你喜欢

转载自blog.csdn.net/u010782846/article/details/79831745