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. 前后端分离后的前端时代
  2. java时间戳转calender_Java获取当前时间,时间戳转换为时间格式 | 学步园
  3. linux性能分析常用的命令
  4. java中遍历树形菜单,你可能不知道还有这样的方法
  5. Autofac在项目中应用的体会,一个接口多个实现的情况
  6. 解决vim编译后的乱码问题
  7. 摩托罗拉投资Android外来往戏开辟商Moblyng
  8. 代理ip填写格式有什么要求?
  9. QTP网管自动化测试框架
  10. undi是什么意思_undefined是什么意思
  11. 软件测试中的Fault、Error和Failure
  12. JDON 论坛上的NETTY贴
  13. 带你玩转kubernetes-k8s(第61篇-Kubernetes之资源紧缺时的Pod驱逐机制)
  14. PAT_乙级_1012_筱筱
  15. On-Premise
  16. 一个JAVA class的秘密
  17. 显示“Hello World”并转换为语音
  18. python不同时间周期k线_python均线周期转换(日线-周线)
  19. ogr 缓冲区_OGR 数据模型
  20. 真约数求法 c语言,怎样求真约数

热门文章

  1. 算法一:求两个数的和
  2. 史上最全面的Neo4j使用指南
  3. erlang四种启动监控策略
  4. thinkphp-add方法错误
  5. GitHub 给安全行业的四大启示
  6. 关于java中普通代码块、构造代码块与静态代码块
  7. Hadoop学习笔记—20.网站日志分析项目案例(一)项目介绍
  8. solr学习之(七)_学习solr的理由(solr的特点和应用领域)
  9. WINHEX的数据结构模板
  10. arm-buildroot-linux-,buildroot构建交叉编译工具链,根文件系统