可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I want to know way to create singleton class, so that my Util class instantiate only once per app. However when I converted my Java class to kotlin, below code was generated.
Is this correct?
companion object {
private var utilProject: UtilProject? = null
val instance: UtilProject
get() {
if (utilProject == null) utilProject = UtilProject()
return utilProject!!
}
}
I could find a related question, but it is with parameter, and I am not getting it convert without params.
回答1:
Just
companion object {
val instance = UtilProject()
}
will do the job because the companion object itself is a language-level singleton.
(The instance
will be assigned when the companion object is first called.)
-- Updated --
If you need to adjust when the singleton object should be initilized, 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 being initialized before when 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 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).
回答2:
There is a special keyword object
for singletons in Kotlin. You can just type something as simple as this to get working singleton class:
object MySingleton
or when you want some member functions:
object MySingleton {
fun someFunction(...) {...}
}
And then use it:
MySingleton.someFunction(...)
there is a reference: https://kotlinlang.org/docs/reference/object-declarations.html#object-declarations
EDIT:
In your case, you just need to replace in your definition of class UtilProject
to this:
object UtilProject {
// here you put all member functions, values and variables
// that you need in your singleton Util class, for example:
val maxValue: Int = 100
fun compareInts(a: Int, b: Int): Int {...}
}
And then you can simply use your singleton in other places:
UtilProject.compareInts(1, 2)
//or
var value = UtilProject.maxValue
回答3:
Super simple lazy example:
companion object {
val instance: UtilProject by lazy { UtilProject() }
}
回答4:
Only the word object is needed.
object UtilProject {
var bar: Int = 0
fun foo() {
}
}
And you directly access the object that has only one instance
fun main(args: Array<String>) {
UtilProject.bar = 1
println(UtilProject.bar)
}
回答5:
In Kotlin you should get rid of the whole notion of the utility singleton class. The idiomatic way is to simply move all declarations to the top level.
Java:
public final class Util {
public static final Util UTIL = new Util();
private int prefixLength = 4;
private Util() {}
public void setPrefixLength(int newLen) {
prefixLength = newLen;
}
public String extractVin(String input) {
return input.substring(prefixLength);
}
}
Usage:
String vin = UTIL.extractVin("aoeuVN14134230430")
In Kotlin just create a separate file called util.kt
with the following:
var prefixLength = 4
fun String.extractVin() = this.substring(prefixLength)
Usage:
val vin = "aoeuVN14134230430".extractVin()
But... you're polluting the top-level namespace!
If your Java intuition triggers a red flag here, simply remember that the package is the namespacing construct and as opposed to Java, Kotlin doesn't conflate the concerns of namespacing and encapsulation. There's no "package-private" access level so you're free from the burden of deciding that something must stay within the same package so it can be made package-private.
So, where in Java you create a degenerate class as a workaround, in Kotlin you just create a file in its own package.
回答6:
A Singleton
example over retrofit to support the api call.
object RetrofitClient {
private var instance: Api? = null
private val BASE_URL = "https://jsonplaceholder.typicode.com/"
fun getInstance(): Api? {
if (instance == null) {
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
instance = retrofit.create(Api::class.java)
}
return instance
}
}
回答7:
class TestMySingleton private constructor() {
companion object {
var single = TestMySingleton()
fun getInstance(): TestMySingleton {
if (single == null)
single = TestMySingleton()
return single
}
}
}