Singleton with parameter in Kotlin
Here's a neat alternative from Google's architecture components sample code, which uses the also
function:
class UsersDatabase : RoomDatabase() {
companion object {
@Volatile private var INSTANCE: UsersDatabase? = null
fun getInstance(context: Context): UsersDatabase =
INSTANCE ?: synchronized(this) {
INSTANCE ?: buildDatabase(context).also { INSTANCE = it }
}
private fun buildDatabase(context: Context) =
Room.databaseBuilder(context.applicationContext,
UsersDatabase::class.java, "Sample.db")
.build()
}
}
Singleton with argument in Kotlin
Since objects do not have constructors what I have done the following to inject the values on an initial setup. You can call the function whatever you want and it can be called at any time to modify the value (or reconstruct the singleton based on your needs).
object Singleton {
private var myData: String = ""
fun init(data: String) {
myData = data
}
fun singletonDemo() {
System.out.println("Singleton Data: ${myData}")
}
}
Singleton class in Kotlin
Just
companion object {
val instance = UtilProject()
}
will do the job because the companion object itself is a language-level singleton.
(The instance
will be created when the companion object is first called.)
-- Updated --
If you need to control when the singleton object is initialized, you can create one object for each class.
class UtilProject {
....
companion object {
val instance = UtilProject()
}
}
class AnotherClass {
...
companion object {
val instance = AnotherClass()
const val abc = "ABC"
}
}
fun main(args: Array<String>) {
val a = UtilProject.instance // UtilProject.instance will be initialized here.
val b = AnotherClass.abc // AnotherClass.instance will be initialized here because AnotherClass's companion object is instantiated.
val c = AnotherClass.instance
}
Here, AnotherClass.instance
is initialized before AnotherClass.instance
is actually called. It is initialized when AnotherClass
's companion object is called.
To prevent it from being initialized before when it is needed, you can use like this:
class UtilProject {
....
companion object {
fun f() = ...
}
}
class AnotherClass {
...
companion object {
const val abc = "ABC"
}
}
object UtilProjectSingleton {
val instance = UtilProject()
}
object AnotherClassSingleton {
val instance = AnotherClass()
}
fun main(args: Array<String>) {
UtilProject.f()
println(AnotherClass.abc)
val a = UtilProjectSingleton.instance // UtilProjectSingleton.instance will be initialized here.
val b = AnotherClassSingleton.instance // AnotherClassSingleton.instance will be initialized here.
val c = UtilProjectSingleton.instance // c is a.
}
If you don't care when each singleton is initialized, you can also use it like this:
class UtilProject {
....
companion object {
fun f() = ...
}
}
class AnotherClass {
...
companion object {
const val abc = "ABC"
}
}
object Singletons {
val utilProject = UtilProject()
val anotherClass = AnotherClass()
}
fun main(args: Array<String>) {
val a = Singletons.utilProject
val b = Singletons.anotherClass
}
In summary,
an object
or a companion object
is one singleton object in Kotlin.
You can assign variables in an object or objects, and then use the variables just like they were singletons.
object
or companion object
is instantiated when it is first used.val
s and var
s in an object
are initialized when the object
is first instantiated (i.e., when the object
is first used).
EDIT:
William Hu said in the comment that "a companion object
is when the class is loaded."
Kotlin Singletons: Object vs a Class with private constructor
Using an object
is an issue if your singleton instance needs parameters, like in this case here, with GardenPlantingDao
, as they cannot take constructor arguments. This comes up frequently on Android, as there's many cases where singletons requires a Context
to operate.
You could still use an object
in these cases, but it would either be unsafe or inconvenient:
- The first option would be to provide it with its dependencies using a setter method before using any of its other methods. This would mean that every other method would have to check if the dependencies have been initialized, and probably throw exceptions in case they haven't, which leads to runtime problems.
- Alternatively, you could require any dependencies as arguments to each method of the singleton, which is tedious at the call site.
Hence the "traditional" way of implementing a singleton with a private constructor and a factory method instead.
Kotlin thread safe native lazy singleton with parameter
Kotlin has an equivalent of your Java code, but more safe. Your double lock check is not recommended even for Java. In Java you should use an inner class on the static which is also explained in Initialization-on-demand holder idiom.
But that's Java. In Kotlin, simply use an object (and optionally a lazy delegate):
object Singletons {
val something: OfMyType by lazy() { ... }
val somethingLazyButLessSo: OtherType = OtherType()
val moreLazies: FancyType by lazy() { ... }
}
You can then access any member variable:
// Singletons is lazy instantiated now, then something is lazy instantiated after.
val thing = Singletons.something // This is Doubly Lazy!
// this one is already loaded due to previous line
val eager = Singletons.somethingLazyButLessSo
// and Singletons.moreLazies isn't loaded yet until first access...
Kotlin intentionally avoids the confusion people have with singletons in Java. And avoids the "wrong versions" of this pattern -- of which there are many. It instead provides the simpler and the safest form of singletons.
Given the use of lazy()
, if you have other members each would individually be lazy. And since they are initialized in the lambda passed to lazy()
you can do things that you were asking about for about customizing the constructor, and for each member property.
As a result you have lazy loading of Singletons
object (on first access of instance), and then lazier loading of something
(on first access of member), and complete flexibility in object construction.
See also:
lazy()
function- Lazy thread safe mode options
- Object declarations
As a side note, look at object registry type libraries for Kotlin that are similar to dependency injection, giving you singletons with injection options:
- Injekt - I'm the author
- Kodein - Very similar and good
Related Topics
How to Add Android Support V7 Libraries in Eclipse
How to Default to Numeric Keyboard on Edittext Without Forcing Numeric Input
How to Link a Prebuilt Shared Library to an Android Ndk Project
Listening for Action_Screen_Off
Why "This App Has Been Built with an Incorrect Configuration" Error Occured in Some Phones
Android: Volley Http Request Custom Header
Firebase:Differencebetween Setpersistenceenabled and Keepsynced
What Is the Use of Movetofirst () in SQLite Cursors
Change Background Color of Android Menu
Android, Move Bitmap Along a Path
Android Java.Lang.Illegalstateexception: Couldn't Read Row 0, Col 0 from Cursorwindow
Error Inflating Class and Android.Support.V7.Widget.Cardview
How to Write a Drawable Resource to a File
How to Change the Background of Android Alert Dialogs
How to Write a Custom Filter for Listview with Arrayadapter
Voice Detection in Android Application
Android Studio Fails to Build New Project, Timed Out While Wating for Slave Aapt Process