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:@Singleton@Providescom.google.gson.Gson 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

 

 

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值