@Singleton能保证单例吗

栏目: Android · 发布时间: 5年前

内容简介:答案是不完全能(或者是说是有条件的能)当你不使用@Singleton时,在同一个宿主类里,注入两次同一个类的对象你会发现,两个对象的地址不一样当你使用了@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

@Singleton能保证单例吗

然后实现了PetComponen接口里的注入方法,这里会通过上面得到的main2ActivityMembersInjector,main3ActivityMembersInjector,baseActivityMembersInjector去实现

@Singleton能保证单例吗

可见,每次构建新的DaggerPetComponent,都会有新的providesPetProvider产生,导致main2ActivityMembersInjector,main3ActivityMembersInjector,baseActivityMembersInjector里所保存的注入实例是不同的,导致在不同的DaggerPetComponent所管理的对象之间不是单例

二、使用了Singleton后注解的,

  1. 这是DaggerPetComponent类

    @Singleton能保证单例吗
  2. 我们点击DoubleCheck看看

    @Singleton能保证单例吗

    我们看到,通过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() {
    @Inject
    lateinit var pet: Pet
    @Inject
    lateinit var pet1: Pet

    override 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里的petComponent
        bt.setOnClickListener {

            Log.e("ccc", pet.toString())
            Log.e("ccc", pet1.toString())

        }
        bt1.setOnClickListener {

            startActivity(Intent(this, Main3Activity::class.java))
        }
    }
}
复制代码
class Main3Activity : BaseActivity() {
    @Inject
    lateinit var pet: Pet
    @Inject
    lateinit var pet1: Pet

    override 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里的petComponent
        Log.e("ccc", "pet${pet.toString()}")
        Log.e("ccc", "pet${pet1.toString()}")
    }
}

复制代码

结果是全局单例

@Singleton能保证单例吗

二、Component不再是一个接口了,把它改造成一个抽象类,在抽象类里实现本类的单例

@Component(modules = [PetModule::class])
@Singleton

abstract class PetComponent {
    companion object {
        private  var mComponent: PetComponent? =null
        fun 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() {
    @Inject
    lateinit var pet: Pet
    @Inject
    lateinit var pet1: Pet

    override 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() {
    @Inject
    lateinit var pet: Pet
    @Inject
    lateinit var pet1: Pet

    override 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不能同时使用所以使用了上面的两次判空的经典单例写法

@Singleton能保证单例吗

以上所述就是小编给大家介绍的《@Singleton能保证单例吗》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Web Designer's Idea Book

The Web Designer's Idea Book

Patrick Mcneil / How / 2008-10-6 / USD 25.00

The Web Designer's Idea Book includes more than 700 websites arranged thematically, so you can find inspiration for layout, color, style and more. Author Patrick McNeil has cataloged more than 5,000 s......一起来看看 《The Web Designer's Idea Book》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

在线进制转换器
在线进制转换器

各进制数互转换器

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码