Dagger 2 - what is the purpose of a @Singleton annotation class

后端 未结 5 866
既然无缘
既然无缘 2021-02-03 17:43

From the dagger 2 Documentation I noticed that you can have a @Singleton annotated class. What is the purpose of marking a class as @Singleton as I hav

5条回答
  •  情歌与酒
    2021-02-03 17:59

    What is singleton?

    Singleton Pattern in android

    A single instance of a class providing a global point of access to itself during the entire application's lifetime.

    @Singleton annotation in Dagger

    A single instance of a class which is unique to a specific component, its access is limited to the scope of the component.

    Purpose of singleton

    To provide a single instance of a class within the dependency graph(component). a component is usually initialized in the application level as it executes only ones for the entire applications lifetime and is accessible by all activities and fragment.

    Let's take an example:

    CoffeeComponent.kt

    @Singleton
    @Component
    interface CoffeeComponent {
    
      fun getCoffeeMaker():CoffeeMaker
      fun inject(activityA: ActivityA)
      fun inject(activityB: ActivityB)
    }
    

    CoffeeMaker.kt

    @Singleton
    class CoffeeMaker @Inject constructor()
    

    CoffeeAplication.kt

    class CoffeeApplication : Application() {
    
      private val component by lazy {
        DaggerCoffeeComponent.builder().build()
      }
    
      fun getAppComponent(): CoffeeComponent = component
    }
    

    Recommended Practise

    Always go for lazy initialization of your component.
    Scenario: say, you are team decided to add an onboarding/tutorial screen or incorporate some other design which doesn't require the component during the initial screens, it will help minimize the startup delay. Always remember, component initialization is expensive.

    ActivityA.kt

    import dagger.Lazy
    
    class ActivityA: AppCompatActivity() {
    
      @Inject
      lateinit var coffeeMaker1:Lazy
      @Inject
      lateinit var coffeeMaker2:Lazy
      private val component by lazy {
        (application as CoffeeApplication).getAppComponent()
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        btn_activityB.setOnClickListener { startActivity(Intent(this, NewActivity::class.java)) }
    
        component.inject(this)
    
        println("Activity A CoffeeMaker 1 - ${coffeeMaker1.get()}")
        println("Activity A CoffeeMaker 2 - ${coffeeMaker2.get()}")
      }
    }
    


    If your class is expensive to construct, use the dagger's Lazy initialization, please don't confuse it with kotlin's Lazy. You have to import

    import dagger.Lazy

    @Inject
    lateinit var coffeeMaker1:Lazy
    

    ActivityB.kt

    class ActivityB: AppCompatActivity() {
    
    @Inject
    lateinit var coffeeMaker1:Lazy
    @Inject
    lateinit var coffeeMaker2:Lazy
    private val component by lazy { 
    (application as CoffeeApplication).getAppComponent() }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_new)
        component.inject(this)
    
        println("Activity B CoffeeMaker 1 - ${coffeeMaker1.get()}")
        println("Activity B CoffeeMaker 2 - ${coffeeMaker2.get()}")
    }
    }
    

    you will get the Log output as

    Note:

    If you want to share a singleton instance between activities, lazily initialize them in the application level, if you initialize them in an activity you will end up with different instance as the components are different

提交回复
热议问题