前言
Dagger2进阶-范围的控制(Scope和Singleton)
注解解释
@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