Reputation: 3976
Help! I have a leak (at least I think so...)
The instance
value below is my "port" into this class from static companion object. I had some thoughts of using applicationContext in some way (my TODO: comment)... because I get this memory leak warning... :
To avoid this problem, and at the same time not needing the context parameter in every call to theese functions (I want to store the context in the class somehow, and get disposed of it when it dies), is there any good practice to the problem ?
...
class Repository private constructor(
var context: Context
)
{
/**
* Repository class, class for all communication between database and external
* sources
* */
private val TAG = javaClass.simpleName
val appDatabase: AppDatabase = AppDatabase.getInstance(context.applicationContext)
//TODO: Test if better with applicationContext?
companion object {
private val TAG = this::class.java.simpleName
@Volatile private var instance:Repository ?=null
fun getInstance(context: Context)= instance
?: synchronized(this){
instance
?:Repository(context).also { instance = it }
}
fun liveDataUserResult(staffId: StaffType=StaffType.DRIVER) =
instance?.liveDataUserResult(staffId = staffId)
fun liveDataDepartmentResult(staffId: StaffType=StaffType.DRIVER) =
instance?.liveDataDepartmentResult(staffId = staffId)
...
fun liveDataGalleryItemSiteNoInUserPath() = instance?.liveDataGalleryItemSiteNoInUserPath()
...
}
fun liveDataGalleryItemSiteNoInUserPath() =
appDatabase.galleryItemDao().liveDataGalleryItemSiteNoInUserPath(allText = context.getString(R.string.repository_all_text))
}
Upvotes: 2
Views: 3773
Reputation: 3976
All credits to ADM and @Henry Twist above for an excellent answer (as I have accepted), but I will post my result here:
class Repository private constructor(
context: Context
)
{
/**
* Repository class, class for all communication between database and external
* sources
* */
private val TAG = javaClass.simpleName
val applicationContext: Context = context.applicationContext
val appDatabase: AppDatabase = AppDatabase.getInstance(applicationContext)
companion object {
private val TAG = this::class.java.simpleName
@Volatile private var instance:Repository ?=null
fun getInstance(context: Context)= instance
?: synchronized(this){
instance
?:Repository(context).also { instance = it }
}
fun liveDataUserResult(staffId: StaffType=StaffType.DRIVER) =
instance?.liveDataUserResult(staffId = staffId)
fun liveDataDepartmentResult(staffId: StaffType=StaffType.DRIVER) =
instance?.liveDataDepartmentResult(staffId = staffId)
...
fun liveDataGalleryItemSiteNoInUserPath() = instance?.liveDataGalleryItemSiteNoInUserPath()
...
}
fun liveDataGalleryItemSiteNoInUserPath() =
appDatabase.galleryItemDao().liveDataGalleryItemSiteNoInUserPath(allText = applicationContext.getString(R.string.repository_all_text))
}
And, of course Dagger2 or Dagger-HILT will be more elegant.
Upvotes: 1
Reputation: 21053
Do not pass Context
in the Repository
except pass AppDatabase
instance directly.
AppDatabase
is used as Singleton
throughout the application So you just initiate it once probably in Application class or in some other Singleton
, and use the same Object
everywhere.
It will be easy to create/inject Dependencies if you use any dependency injection framework like Dagger2 or Dagger-Hilt.
You can remove var for constructor field to make it work then it will not hold the reference globally. Thx to @Henry Twist .
class Repository private constructor(context: Context) {
private val TAG = javaClass.simpleName
var appDatabase: AppDatabase = AppDatabase.getInstance(context.applicationContext)
companion object {
@Volatile
private var instance: Repository? = null
@JvmStatic
fun getInstance(context: Context) = instance
?: synchronized(this) {
instance
?: Repository(context).also { instance = it }
}
}
}
Upvotes: 2