答案是不徹底能(或者是說是有條件的能)java
當你不使用@Singleton時,在同一個宿主類裏,注入兩次同一個類的對象你會發現,兩個對象的地址不同bash
當你使用了@Singleton,在同一個宿主類裏,注入兩次同一個類的對象你會發現,兩個對象的地址變得同樣了ide
可是使用了@Singleton後,此時你在另外一個宿主內,再次注入兩次同一個類的對象你會發現,兩個對象的地址在本宿主內是同樣的,可是與以前的那個宿主裏的對象地址是不一樣的ui
爲何會這樣的呢,答案是當你使用了@Singleton後,你所注入的對象是經過Component管理的,只要是同一個Component管理到的,且通過@Singleto註解後的對象,不管注入幾個都是同一個地址(也就是單例)this
可是上面咱們在新的宿主裏,又從新new了個Component,因此新宿主裏的兩個對象是在新的Component所管理的,他們地址是同樣的,而他們與第一個宿主以前的Component是不一樣的,因此地址會不同spa
因此,結論來了,在同一個Component管理的對象,若是沒了@Singleton註解了,那麼他仍是單例,不一樣Component所管理的對象,即便是@Singleton註解過了,依然不是單例3d
這是DaggerPetComponent類code
先獲得providesPetProvider實例,而後在不一樣的宿主類(本例是Main2Activity,Main3Activity,BaseActivity)經過providesPetProvider,獲得相應的main2ActivityMembersInjector,main3ActivityMembersInjector,baseActivityMembersInjectorcomponent
而後實現了PetComponen接口裏的注入方法,這裏會經過上面獲得的main2ActivityMembersInjector,main3ActivityMembersInjector,baseActivityMembersInjector去實現cdn
可見,每次構建新的DaggerPetComponent,都會有新的providesPetProvider產生,致使main2ActivityMembersInjector,main3ActivityMembersInjector,baseActivityMembersInjector裏所保存的注入實例是不一樣的,致使在不一樣的DaggerPetComponent所管理的對象之間不是單例
這是DaggerPetComponent類
咱們點擊DoubleCheck看看
咱們看到,經過DoubleCheck保證了providesPetProvider是單例,而後使用同一個providesPetProvider,產生的對應的main2ActivityMembersInjector,main3ActivityMembersInjector,baseActivityMembersInjector裏面實際保存的是相同的對象實例,從而實現了跨DaggerPetComponent間的單例答案:全局保證明例化一個Component,而後全部的注入對象都是經過這個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()}")
}
}
複製代碼
結果是全局單例
@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裏單例模式只需一個object便可
即把class改成object,kotlin內部就會把這個類改成單例 可是惋惜,我們的PetComponent必須包含抽象方法,那麼這個類必須是abstract的,可是 abstract object不能同時使用因此使用了上面的兩次判空的經典單例寫法