Reputation: 2164
Trying to use Singleton class in another Singleton, but somehow it gives me memory leaks.
How could i improve it?
Here is my example singleton implementation
class FirstSingletonClass(val context: Context) {
companion object {
@Volatile
private var instance: FirstSingletonClass? = null
fun getInstance(context: Context): FirstSingletonClass =
instance ?: synchronized(this) {
instance ?: FirstSingletonClass(context).also { instance = it }
}
}
private val sSingletonClass: SecondSingletonClass = Injection.provideSecondSingletonClass(context)
}
SecondSingletonClass block
class SecondSingletonClass(val context: Context) {
companion object {
@Volatile
private var instance: SecondSingletonClass? = null
fun getInstance(context: Context): SecondSingletonClass =
instance ?: synchronized(this) {
instance ?: SecondSingletonClass(context).also { instance = it }
}
}
private val fSingletonClass: FirstSingletonClass = Injection.provideFirstSingletonClass(context)
}
Injection class
object Injection {
fun provideSecondSingletonClass(context: Context): SecondSingletonClass = SecondSingletonClass.getInstance(context)
fun provideFirstSingletonClass(context: Context): FirstSingletonClass = FirstSingletonClass.getInstance(context)
}
So when im initializing property - private val sSingletonClass
or private val fSingletonClass
it's produces memory leaks. But if i will call my singleton class somewhere in function block it works fine.
Is that possible to achieve what i want? Or should i use it explicitly...
Upvotes: 1
Views: 1815
Reputation: 14173
Problem: You are passing the Context instance into the Singleton, the context might be an activity, a service, etc. It might make the context from leaking.
Solution: Using applicationContext
instead.
class FirstSingletonClass(val context: Context) {
companion object {
@Volatile
private var instance: FirstSingletonClass? = null
fun getInstance(context: Context): FirstSingletonClass =
instance ?: synchronized(this) {
instance ?: FirstSingletonClass(context.applicationContext).also { instance = it }
}
}
private val sSingletonClass: SecondSingletonClass = Injection.provideSecondSingletonClass(context)
}
class SecondSingletonClass(val context: Context) {
companion object {
@Volatile
private var instance: SecondSingletonClass? = null
fun getInstance(context: Context): SecondSingletonClass =
instance ?: synchronized(this) {
instance ?: SecondSingletonClass(context.applicationContext).also { instance = it }
}
}
private val fSingletonClass: FirstSingletonClass = Injection.provideFirstSingletonClass(context)
}
Upvotes: 2
Reputation: 508
You are leaking a Context here. You should not hold a long-lived reference to a Context. You can instead have the Context as an argument in the methods of FirstSingletonClass and SecondSingletonClass that need them.
Android studio should give you this warning:
Do not place Android context classes in static fields (static reference to SecondSingletonClass which has field context pointing to Context); this is a memory leak (and also breaks Instant Run)
Your code can be simplified to this:
object FirstSingletonClass {
private val sSingletonClass = SecondSingletonClass
}
object SecondSingletonClass {
private val fSingletonClass = FirstSingletonClass
}
Upvotes: 2