科特林的单例课程

时间:2018-08-14 06:29:47

标签: android kotlin

我想知道创建单例类的方法,以便每个应用程序的Util类仅实例化一次。但是,当我将Java类转换为kotlin时,生成了以下代码。

这正确吗?

companion object {
    private var utilProject: UtilProject? = null

    val instance: UtilProject
        get() {
            if (utilProject == null) utilProject = UtilProject()
            return utilProject!!
        }
} 

我可以找到一个相关的 question ,但这是带有参数的,并且我无法在没有参数的情况下进行转换。

10 个答案:

答案 0 :(得分:18)

在Kotlin中,有一个特殊的关键字object用于单身人士。您可以输入像这样简单的内容来使单例类正常工作:

object MySingleton

或当您需要某些成员函数时:

object MySingleton {
    fun someFunction(...) {...}
}

然后使用它:

MySingleton.someFunction(...)

有一个参考文献:https://kotlinlang.org/docs/reference/object-declarations.html#object-declarations

答案 1 :(得分:12)

只是

companion object {
    val instance = UtilProject()
} 

可以完成此任务,因为伴侣对象本身是语言级别的单例。
(在首先 调用伴随对象时将分配instance。)

-更新-

如果需要调整何时初始化单例对象,则可以为每个类创建一个对象。

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
}

在这里,AnotherClass.instance在实际调用AnotherClass.instance之前被初始化。在调用AnotherClass的伴随对象时初始化它。 为了避免在需要时进行初始化,可以这样使用:

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.
}

如果您不关心何时初始化每个单例,也可以这样使用:

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 
}

总而言之,
objectcompanion object是Kotlin中的一个单例对象。
您可以在 object objects 中分配变量,然后像使用单例一样使用变量。

objectcompanion object在首次使用时被实例化。 val中的varobject s在首次实例化object时(即,第一次使用object时)被初始化。

答案 2 :(得分:2)

在Kotlin中,您应该摆脱实用程序单例类的整个概念。惯用的方法是简单地将所有声明移到顶层。

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);
    }
}

用法:

String vin = UTIL.extractVin("aoeuVN14134230430")

在Kotlin中,只需创建一个名为util.kt的独立文件,其中包含以下内容:

var prefixLength = 4

fun String.extractVin() = this.substring(prefixLength)

用法:

val vin = "aoeuVN14134230430".extractVin()

但是...您正在污染顶级名称空间!

如果您的Java直觉在这里触发了一个危险信号,只需记住 package 是命名空间构造,并且与Java相反,Kotlin不会混淆命名空间和封装的问题。没有“ package-private”访问级别,因此您无需负担必须将某些内容保留在同一包中以便可以将其设置为package-private的负担。

因此,在Java中创建退化类作为解决方法的地方,在Kotlin中,只需在其自己的包中创建文件。

答案 3 :(得分:2)

仅需要单词对象。

object UtilProject {
    var bar: Int = 0
    fun foo() {        
    }
}

您直接访问只有一个实例的对象

fun main(args: Array<String>) {
    UtilProject.bar = 1
    println(UtilProject.bar)    
}

答案 4 :(得分:1)

超级简单的懒惰示例:

ENOSPC

答案 5 :(得分:1)

 class TestMySingleton private constructor() {
​
   companion object {
        var single = TestMySingleton()

        fun getInstance(): TestMySingleton {
            if (single == null)
                single = TestMySingleton()
            return single
        }
    }

}

答案 6 :(得分:1)

带参数的变体

open class SingletonHolder<out T: Any, in A>(creator: (A) -> T) {
    private var creator: ((A) -> T)? = creator
    @Volatile private var instance: T? = null

    fun getInstance(arg: A): T {
        val checkInstance = instance
        if (checkInstance != null) {
            return checkInstance
        }

        return synchronized(this) {
            val checkInstanceAgain = instance
            if (checkInstanceAgain != null) {
                checkInstanceAgain
            } else {
                val created = creator!!(arg)
                instance = created
                creator = null
                created
            }
        }
    }
}


答案 7 :(得分:0)

经过翻新以支持api调用的Singleton示例。

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
    }
}

答案 8 :(得分:0)

class MyClass {


    init {
        println("init is called")
    }

    companion object {

        private var obj: MyClass? = null
        fun getInstance(): MyClass {
            if (obj == null) {
                obj = MyClass()
            }
            return obj as MyClass 
        }

    }

    fun printHello() {
        println("Hello World")
    }

您可以通过MyClass.getInstance()来创建其实例,例如java

答案 9 :(得分:0)

这会有所帮助。我正在使用 Dialog 类,但您可以使用示例了解如何实现。

class MyClass(context: Context) : Dialog(context) {
    companion object {
    lateinit var INSTANCE: MyClass

    @JvmStatic
    fun getInstance(context: Context): MyClass{
        if (!::INSTANCE.isInitialized) {
            INSTANCE = MyClass(context)
        }

        return INSTANCE
    }
}}