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后注解的,

  1. 这是DaggerPetComponent类

  2. 我们点击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能保证单例吗相关推荐

  1. socket可以写成单例嘛_精读《设计模式 - Singleton 单例模式》

    Singleton(单例模式) Singleton(单例模式)属于创建型模式,提供一种对象获取方式,保证在一定范围内是唯一的. 意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 其实单例模 ...

  2. socket可以写成单例嘛_精读设计模式 Singleton 单例模式

    Singleton(单例模式) Singleton(单例模式)属于创建型模式,提供一种对象获取方式,保证在一定范围内是唯一的. 意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 其实单例模 ...

  3. 什么是Singleton,单例设计模式

    Singleton  [ˈsɪŋɡltən] 单例模式 在java中是指单例设计模式. 单例设计模式: 单例模式可以保证系统中,应用该模式的类一个类只有一个实例.即一个类只有一个对象实例. 例如:例如 ...

  4. 单例Singleton

    先提供一个完整版: // .h文件 @interface SingleTon : NSObject /** 获取单例对象*/ + (instancetype)sharedInstance; + (in ...

  5. 单例/单体模式(Singleton)

    单例/单体模式(Singleton) 首先,单例模式是对象的创建模式之一,此外还包括工厂模式.单例模式的三个特点: 1,该类只有一个实例 2,该类自行创建该实例(在该类内部创建自身的实例对象) 3,向 ...

  6. Swift中编写单例的正确方式

    本文由CocoaChina译者leon(社区ID)翻译自krakendev 原文:THE RIGHT WAY TO WRITE A SINGLETON 转载请保持所有内容和链接的完整性. 在之前的帖子 ...

  7. android 单例的作用,Android中单例模式的几个坑

    先来看这样一个单例,稍微有点经验的同学可能都会说,这样的单例是非线程安全的.要加个volatile关键字才可以.class Singleton{        private static  Sing ...

  8. 为什么我强烈建议大家使用枚举来实现单例

    转载自   为什么我墙裂建议大家使用枚举来实现单例 关于单例模式,我的博客中有很多文章介绍过.作为23种设计模式中最为常用的设计模式,单例模式并没有想象的那么简单.因为在设计单例的时候要考虑很多问题, ...

  9. 漫画:什么是单例设计模式

    转载自 永远爱大家的 程序员小灰 -----  第二天  ----- 单例模式第一版: 1 2 3 4 5 6 7 8 9 10 11 public class Singleton {     pri ...

最新文章

  1. linux 入门-1
  2. 购物车的实现(jsp的session+Java的Map的结合)
  3. redis 读取mysql数据类型_认识Redis与Redis的数据类型
  4. DDoS攻击愈演愈烈,反射攻击举足轻重
  5. 趣图:BAT程序员的一天对比
  6. 洪水同频率放大的方法_我们应该怎么选择放大器配件?
  7. 数据结构之字符串反转
  8. SpringBoot 启动失败 Failed to determine a suitable driver class 问题解决方案
  9. 强大的端到端语音识别框架—RNN-T
  10. 数组、字典转json串,不支持字符串
  11. 【Codeforces Round #546 (Div. 2) E】Nastya Hasn't Written a Legend【线段树】
  12. 解决RHEL6 vncserver 启动 could not open default font 'fixed'错误.
  13. 【C语言】c语言基础知识梳理(超全)
  14. 禁止MAC Chrome更新
  15. kubernetes节点NotReady
  16. Oracle 轻量级实时监控工具 oratop
  17. 佳能数码相机,不能安装驱动程序
  18. 【python教程】揭秘京东|淘宝秒杀抢购背后的黑幕,为什么你总抢不到商品?
  19. 复现东方证券研报--特质波动率因子研究
  20. LTE终端分类-LTE UE category

热门文章

  1. golang中的权限
  2. golang中的recover
  3. shell实例第11讲:取出系统IP地址,并判断属于哪个网段
  4. 深入理解TCP/IP协议族
  5. 已解决:IAR编译时出现duplicate definitions for IAR报错
  6. springmvc二十九:拦截器
  7. 前端一HTML:十三:css的三大特性
  8. Python简单主机批量管理工具
  9. ubuntu中安装ffmpeg+mencoder转换flv -
  10. CentOS 7下的MariaDB Master-Slave Replication配置