@Singleton能保证单例吗
scope里有个@Singleton,它能保证单例吗?
答案是不完全能(或者是说是有条件的能)
当你不使用@Singleton时,在同一个宿主类里,注入两次同一个类的对象你会发现,两个对象的地址不一样
当你使用了@Singleton,在同一个宿主类里,注入两次同一个类的对象你会发现,两个对象的地址变得一样了
但是使用了@Singleton后,此时你在另一个宿主内,再次注入两次同一个类的对象你会发现,两个对象的地址在本宿主内是一样的,但是与之前的那个宿主里的对象地址是不同的
为什么会这样的呢,答案是当你使用了@Singleton后,你所注入的对象是通过Component管理的,只要是同一个Component管理到的,且经过@Singleto注解后的对象,无论注入几个都是同一个地址(也就是单例)
但是上面我们在新的宿主里,又重新new了个Component,所以新宿主里的两个对象是在新的Component所管理的,他们地址是一样的,而他们与第一个宿主之前的Component是不同的,所以地址会不一样
所以,结论来了,在同一个Component管理的对象,如果没了@Singleton注解了,那么他还是单例,不同Component所管理的对象,即使是@Singleton注解过了,依然不是单例
来看看源码
一、没使用Singleton注解的
这是DaggerPetComponent类
先得到providesPetProvider实例,然后在不同的宿主类(本例是Main2Activity,Main3Activity,BaseActivity)通过providesPetProvider,得到相应的main2ActivityMembersInjector,main3ActivityMembersInjector,baseActivityMembersInjector
然后实现了PetComponen接口里的注入方法,这里会通过上面得到的main2ActivityMembersInjector,main3ActivityMembersInjector,baseActivityMembersInjector去实现
可见,每次构建新的DaggerPetComponent,都会有新的providesPetProvider产生,导致main2ActivityMembersInjector,main3ActivityMembersInjector,baseActivityMembersInjector里所保存的注入实例是不同的,导致在不同的DaggerPetComponent所管理的对象之间不是单例
二、使用了Singleton后注解的,
这是DaggerPetComponent类
我们点击DoubleCheck看看
我们看到,通过DoubleCheck保证了providesPetProvider是单例,然后使用同一个providesPetProvider,产生的对应的main2ActivityMembersInjector,main3ActivityMembersInjector,baseActivityMembersInjector里面实际保存的是相同的对象实例,从而实现了跨DaggerPetComponent间的单例
问题来了,如何保证全局单例呢
答案:全局保证实例化一个Component,然后所有的注入对象都是通过这个Component来管理,方法有二:
一、在Application里实例化一个Component
因为Application执行一次,从而保证里全局只有一个Component
class MyApplication :Application(){companion object{val petComponent = DaggerPetComponent.create()//初始化petComponent}override fun onCreate() {super.onCreate()}
}复制代码
class Main2Activity : BaseActivity() {@Injectlateinit var pet: Pet@Injectlateinit var pet1: Petoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main2)
// DaggerPetComponent.builder().petModule(PetModule()).build().inject(this)//不要这样注入,这样是new了新的petComponent,就不是全局单例了MyApplication.petComponent.inject(this)//要使用MyApplication里的petComponentbt.setOnClickListener {Log.e("ccc", pet.toString())Log.e("ccc", pet1.toString())}bt1.setOnClickListener {startActivity(Intent(this, Main3Activity::class.java))}}
}
复制代码
class Main3Activity : BaseActivity() {@Injectlateinit var pet: Pet@Injectlateinit var pet1: Petoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main3)// DaggerPetComponent.builder().petModule(PetModule()).build().inject(this)//不要这样注入,这样是new了新的petComponent,就不是全局单例了MyApplication.petComponent.inject(this)//要使用MyApplication里的petComponentLog.e("ccc", "pet${pet.toString()}")Log.e("ccc", "pet${pet1.toString()}")}
}复制代码
结果是全局单例
二、Component不再是一个接口了,把它改造成一个抽象类,在抽象类里实现本类的单例
@Component(modules = [PetModule::class])
@Singletonabstract class PetComponent {companion object {private var mComponent: PetComponent? =nullfun getInstance(): PetComponent? {if (mComponent == null) {synchronized(PetComponent::class.java) {if (mComponent == null) {mComponent = DaggerPetComponent.create()}}}return mComponent}}abstract fun inject(activity: Main2Activity)abstract fun inject(activity: Main3Activity)
}
复制代码
class Main2Activity : BaseActivity() {@Injectlateinit var pet: Pet@Injectlateinit var pet1: Petoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main2)PetComponent.getInstance()!!.inject(this)//单例注入bt.setOnClickListener {Log.e("ccc", pet.toString())Log.e("ccc", pet1.toString())}bt1.setOnClickListener {startActivity(Intent(this, Main3Activity::class.java))}}
}
复制代码
class Main3Activity : BaseActivity() {@Injectlateinit var pet: Pet@Injectlateinit var pet1: Petoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main3)// DaggerPetComponent.builder().petModule(PetModule()).build().inject(this)
// MyApplication.petComponent.inject(this)PetComponent.getInstance()!!.inject(this)//单例注入Log.e("ccc", "pet${pet.toString()}")Log.e("ccc", "pet${pet1.toString()}")}
}复制代码
说说kotlin的单例模式
其实在kotlin里单例模式只需一个object即可
即把class改为object,kotlin内部就会把这个类改为单例 但是可惜,咱们的PetComponent必须包含抽象方法,那么这个类必须是abstract的,但是 abstract object不能同时使用所以使用了上面的两次判空的经典单例写法
参考
详解 Dagger2 的 @Scope 和 @Subcomponent
@Singleton能保证单例吗相关推荐
- socket可以写成单例嘛_精读《设计模式 - Singleton 单例模式》
Singleton(单例模式) Singleton(单例模式)属于创建型模式,提供一种对象获取方式,保证在一定范围内是唯一的. 意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 其实单例模 ...
- socket可以写成单例嘛_精读设计模式 Singleton 单例模式
Singleton(单例模式) Singleton(单例模式)属于创建型模式,提供一种对象获取方式,保证在一定范围内是唯一的. 意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 其实单例模 ...
- 什么是Singleton,单例设计模式
Singleton [ˈsɪŋɡltən] 单例模式 在java中是指单例设计模式. 单例设计模式: 单例模式可以保证系统中,应用该模式的类一个类只有一个实例.即一个类只有一个对象实例. 例如:例如 ...
- 单例Singleton
先提供一个完整版: // .h文件 @interface SingleTon : NSObject /** 获取单例对象*/ + (instancetype)sharedInstance; + (in ...
- 单例/单体模式(Singleton)
单例/单体模式(Singleton) 首先,单例模式是对象的创建模式之一,此外还包括工厂模式.单例模式的三个特点: 1,该类只有一个实例 2,该类自行创建该实例(在该类内部创建自身的实例对象) 3,向 ...
- Swift中编写单例的正确方式
本文由CocoaChina译者leon(社区ID)翻译自krakendev 原文:THE RIGHT WAY TO WRITE A SINGLETON 转载请保持所有内容和链接的完整性. 在之前的帖子 ...
- android 单例的作用,Android中单例模式的几个坑
先来看这样一个单例,稍微有点经验的同学可能都会说,这样的单例是非线程安全的.要加个volatile关键字才可以.class Singleton{ private static Sing ...
- 为什么我强烈建议大家使用枚举来实现单例
转载自 为什么我墙裂建议大家使用枚举来实现单例 关于单例模式,我的博客中有很多文章介绍过.作为23种设计模式中最为常用的设计模式,单例模式并没有想象的那么简单.因为在设计单例的时候要考虑很多问题, ...
- 漫画:什么是单例设计模式
转载自 永远爱大家的 程序员小灰 ----- 第二天 ----- 单例模式第一版: 1 2 3 4 5 6 7 8 9 10 11 public class Singleton { pri ...
最新文章
- 前后端分离后的前端时代
- java时间戳转calender_Java获取当前时间,时间戳转换为时间格式 | 学步园
- linux性能分析常用的命令
- java中遍历树形菜单,你可能不知道还有这样的方法
- Autofac在项目中应用的体会,一个接口多个实现的情况
- 解决vim编译后的乱码问题
- 摩托罗拉投资Android外来往戏开辟商Moblyng
- 代理ip填写格式有什么要求?
- QTP网管自动化测试框架
- undi是什么意思_undefined是什么意思
- 软件测试中的Fault、Error和Failure
- JDON 论坛上的NETTY贴
- 带你玩转kubernetes-k8s(第61篇-Kubernetes之资源紧缺时的Pod驱逐机制)
- PAT_乙级_1012_筱筱
- On-Premise
- 一个JAVA class的秘密
- 显示“Hello World”并转换为语音
- python不同时间周期k线_python均线周期转换(日线-周线)
- ogr 缓冲区_OGR 数据模型
- 真约数求法 c语言,怎样求真约数