In Android App, für ein Objekt, das nur einmal erstellt und überall verwendet werden soll, verwenden wir das Singleton Pattern. Das Singleton-Pattern ist ein Software-Entwurfsmuster, das die Instanziierung der Klasse auf „eine“ Instanz beschränkt. Um also das Singleton-Muster in unserem Projekt oder unserer Software zu implementieren, erstellen wir eine Singleton-Klasse. In diesem Blog werden wir lernen, wie man eine Singleton-Klasse in Kotlin erstellt. Also, fangen wir an.
Singleton Klasse
Eine Singleton Klasse ist eine Klasse, die so definiert ist, dass nur eine Instanz der Klasse erstellt und überall verwendet werden kann.
Sie wird dort verwendet, wo nur eine Instanz der Klasse benötigt wird, wie z.B. NetworkService, DatabaseService, etc.
Generell wird es gemacht, weil es die Ressourcen des Systems in Anspruch nimmt, diese Objekte immer wieder zu erstellen. Daher ist es besser, das gleiche Objekt nur einmal zu erstellen und immer wieder zu verwenden.
Eigenschaften einer Singleton-Klasse
Nachfolgend sind die Eigenschaften einer typischen Singleton-Klasse aufgeführt:
- Nur eine Instanz: Die Singleton-Klasse hat nur eine Instanz, und dies geschieht durch die Bereitstellung einer Instanz der Klasse innerhalb der Klasse. Auch sollten äußere Klassen und Unterklassen daran gehindert werden, die Instanz zu erzeugen.
- Globaler Zugriff: Die Instanz der Singleton-Klasse sollte global zugänglich sein, so dass jede Klasse sie nutzen kann.
Regeln für die Erstellung einer Singleton-Klasse
Die folgenden Regeln werden befolgt, um eine Singleton-Klasse zu erstellen:
- Ein privater Konstruktor
- Eine statische Referenz ihrer Klasse
- Eine statische Methode
- Global zugängliche Objektreferenz
- Konsistenz über mehrere Threads hinweg
Singleton Beispiel
Nachfolgend ein Beispiel für eine Singleton Klasse in Java:
public class Singleton { private static Singleton instance = null; private Singleton() { } public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; }}
Wenn wir die Instanz erstellen, um sicherzustellen, dass es keine Thread-Interferenzen gibt, verwenden wir das Schlüsselwort synchronized.
Lassen Sie uns einen Blick auf den Kotlin-Code für dasselbe werfen. Unten ist der Kotlin-Code für die Singleton-Klasse:
object Singleton
Ok, was ist danach zu tun?
Nichts! Machst du Witze? Nein, das ist der Code für die Verwendung der Singleton-Klasse in Kotlin. Sehr einfach? Keine Sorge, schauen wir uns die Erklärung an.
In Kotlin müssen wir das Objekt-Schlüsselwort verwenden, um die Singleton-Klasse zu benutzen. Die Objektklasse kann Funktionen, Eigenschaften und die init-Methode haben. Die Konstruktormethode ist in einem Objekt nicht erlaubt, also können wir die init-Methode verwenden, wenn eine Initialisierung erforderlich ist und das Objekt innerhalb einer Klasse definiert werden kann. Das Objekt wird instanziiert, wenn es zum ersten Mal verwendet wird.
Lassen Sie uns ein Beispiel für die Singleton-Klasse in Kotlin betrachten.
object Singleton{ init { println("Singleton class invoked.") } var variableName = "I am Var" fun printVarName(){ println(variableName) }}fun main(args: Array<String>) { Singleton.printVarName() Singleton.variableName = "New Name" var a = A()}class A { init { println("Class init method. Singleton variableName property : ${Singleton.variableName}") Singleton.printVarName() }}
Hier, im obigen Beispiel, haben wir eine Funktion namens printVarName() und eine Eigenschaft namens „variableName“. Wenn eine Klasse instanziiert wird, können Änderungen in der Objektklasse reflektiert werden. Die Ausgabe des obigen Codes ist also:
Singleton class invoked.I am VarClass init method. Singleton variableName property : New NameNew Name
Objekt, das eine Klasse erweitert
Sie können ein Objekt in Kotlin verwenden, um eine Klasse zu erweitern oder eine Schnittstelle zu implementieren, genau wie eine normale Klasse. Nehmen wir ein Beispiel dafür:
fun main(args: Array<String>) { var a = A() Singleton.printVarName()}open class A { open fun printVarName() { print("I am in class printVarName") } init { println("I am in init of A") }}object Singleton : A() { init { println("Singleton class invoked.") } var variableName = "I am Var" override fun printVarName() { println(variableName) }}
Und die Ausgabe des obigen Codes ist:
I am in init of AI am in init of ASingleton class invoked.I am var
So kann man in den meisten Fällen eine Objektklasse genau wie eine normale Klasse verwenden.
Lernen Sie hier System Design für Ihr nächstes Interview.
Singleton Klasse mit Argument in Kotlin
Im früheren Teil des Blogs haben wir gelernt, dass wir keine Konstruktoren in einer Singleton Klasse haben können. Um etwas zu initialisieren, können wir dies mit init in der Singleton-Klasse tun. Aber was ist, wenn man ein Argument für die Initialisierung übergeben muss, so wie in parametrisierten Konstruktoren? Da wir hier keine Konstruktoren verwenden können. Also müssen wir einen anderen Weg finden, um das Gleiche zu tun.
Wenn wir speziell über Android sprechen, wissen wir, dass wir in Android im Allgemeinen eine Kontextinstanz an den init-Block eines Singletons übergeben müssen. Dies kann mit Early Initialization und Lazy Initialization geschehen. Bei der frühen Initialisierung werden alle Komponenten in Application.onCreate() mit den init()-Funktionen initialisiert. Dies führt jedoch zu einer Verlangsamung des Starts der Anwendung, da der Hauptthread blockiert wird. Daher ist es im Allgemeinen ratsam, die „Lazy Initialization“ zu verwenden. Bei der verzögerten Initialisierung verwenden wir den Kontext als Argument für eine Funktion, die die Instanz des Singletons zurückgibt. Wir können dies durch die Verwendung einer SingletonHolder-Klasse erreichen. Um es thread-sicher zu machen, brauchen wir außerdem eine Möglichkeit der Synchronisation und des doppelt überprüften Lockings.
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 } } }}
Der obige Code ist der effizienteste Code für das doppelt überprüfte Locking-System und der Code ähnelt irgendwie der lazy()-Funktion in Kotlin, weshalb er auch lazy initialization genannt wird. Wann immer man also eine Singleton-Klasse mit Argumenten haben möchte, kann man die SingletonHolder-Klasse verwenden.
Hier, im obigen Code, kann anstelle der Creator-Funktion, die als Argument an den SingletonHolder übergeben wird, auch ein benutzerdefiniertes Lambda inline deklariert werden oder wir können eine Referenz auf den privaten Konstruktor der Singleton-Klasse übergeben. Also, der Code wird sein:
class YourManager private constructor(context: Context) { init { // do something with context } companion object : SingletonHolder<YourManager, Context>(::YourManager)}
Nun kann das Singleton leicht aufgerufen und initialisiert werden, indem man den untenstehenden Code schreibt, und das ist sowohl faul als auch thread-sicher 🙂
YourManager.getInstance(context).doSomething()
Das war’s für den Singleton-Blog. Ich hoffe, dieser Blog hat Ihnen gefallen. Sie können auch auf der Kotlin-Website nachlesen. Um mehr über einige der coolen Themen von Android zu erfahren, können Sie unsere Blogging-Website besuchen und sich unserer Lernreise anschließen.
Keep Learning 🙂
Team MindOrks!