In diesem Thema geht es um einige der nützlichsten Aspekte der Kotlin-Sprache. bei der Entwicklung für Android.
Mit Fragmenten arbeiten
In den folgenden Abschnitten werden Fragment
-Beispiele verwendet, um einige der Kotlin-Funktionen hervorzuheben.
die besten Funktionen.
Inheritance
Sie können eine Klasse in Kotlin mit dem Schlüsselwort class
deklarieren. Im Folgenden
Beispiel: LoginFragment
ist eine abgeleitete Klasse von Fragment
. Sie können angeben,
Vererbung mithilfe des :
-Operators zwischen der Unterklasse und ihrem übergeordneten Element:
class LoginFragment : Fragment()
In dieser Klassendeklaration ist LoginFragment
für das Aufrufen der
Konstruktor der Basisklasse Fragment
.
Innerhalb von LoginFragment
können Sie eine Reihe von Lebenszyklus-Callbacks überschreiben,
auf Statusänderungen in Fragment
reagieren. Verwenden Sie zum Überschreiben einer Funktion die Methode
override
, wie im folgenden Beispiel gezeigt:
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.login_fragment, container, false)
}
Um auf eine Funktion in der übergeordneten Klasse zu verweisen, verwenden Sie das Schlüsselwort super
wie gezeigt
im folgenden Beispiel:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
Null-Zulässigkeit und Initialisierung
In den vorherigen Beispielen haben einige der Parameter in den überschriebenen Methoden
Typen mit einem angehängten Fragezeichen ?
. Das bedeutet, dass die Argumente
für diese Parameter übergebene
Null sein können. Achten Sie darauf,
ihre Null-Zulässigkeit sicher handhaben können.
In Kotlin müssen Sie die Eigenschaften eines Objekts initialisieren, wenn Sie das Objekt deklarieren.
Wenn Sie also eine Instanz einer Klasse abrufen, können Sie sofort
auf ihre barrierefreien Eigenschaften verweisen. Die View
-Objekte in einer Fragment
,
aber erst durch Aufrufen von Fragment#onCreateView
aufgebläht werden.
Sie benötigen eine Möglichkeit, die Initialisierung der Property für ein View
zu verschieben.
Mit lateinit
können Sie die Initialisierung von Properties verzögern. Wenn Sie lateinit
verwenden,
sollten Sie Ihre Property so schnell wie möglich initialisieren.
Im folgenden Beispiel sehen Sie, wie lateinit
verwendet wird, um View
-Objekte in
onViewCreated
:
class LoginFragment : Fragment() {
private lateinit var usernameEditText: EditText
private lateinit var passwordEditText: EditText
private lateinit var loginButton: Button
private lateinit var statusTextView: TextView
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
usernameEditText = view.findViewById(R.id.username_edit_text)
passwordEditText = view.findViewById(R.id.password_edit_text)
loginButton = view.findViewById(R.id.login_button)
statusTextView = view.findViewById(R.id.status_text_view)
}
...
}
Conversion-Tracking für Display-Kampagnen
Sie können Click-Events in Android erfassen, indem Sie die Funktion
OnClickListener
-Schnittstelle. Button
-Objekte enthalten einen setOnClickListener()
-Funktion, die eine OnClickListener
-Implementierung annimmt.
OnClickListener
hat die einzelne abstrakte Methode onClick()
, die Sie ausführen müssen
umsetzen. Weil setOnClickListener()
immer ein OnClickListener
ein Argument, und weil OnClickListener
immer dieselbe einzelne Zusammenfassung hat
kann diese Implementierung mithilfe einer anonymen Funktion in
Kotlin Dieser Prozess wird als
Konvertierung einer einzelnen abstrakten Methode
oder SAM-Konvertierung.
Durch die Umwandlung von Stichproben werden in Ihrem Code deutlich sauberere Codes erstellt. Im folgenden Beispiel
zeigt, wie Sie mithilfe der SAM-Konvertierung ein OnClickListener
für eine
Button
:
loginButton.setOnClickListener {
val authSuccessful: Boolean = viewModel.authenticate(
usernameEditText.text.toString(),
passwordEditText.text.toString()
)
if (authSuccessful) {
// Navigate to next screen
} else {
statusTextView.text = requireContext().getString(R.string.auth_failed)
}
}
Code in der anonymen Funktion, die an setOnClickListener()
übergeben wurde
wird ausgeführt, wenn ein Nutzer auf loginButton
klickt.
Companion-Objekte
Companion-Objekte
bieten einen Mechanismus zum Definieren von Variablen oder Funktionen, die verknüpft sind.
konzeptionell an einen Typ an,
sind aber nicht an ein bestimmtes Objekt gebunden. Companion-Anzeige
-Objekten ähneln der Verwendung des Java-Schlüsselworts static
für Variablen und Methoden.
Im folgenden Beispiel ist TAG
eine String
-Konstante. Sie benötigen keine eindeutige
Instanz von String
für jede Instanz von LoginFragment
, daher sollten Sie
in einem Companion-Objekt definieren:
class LoginFragment : Fragment() {
...
companion object {
private const val TAG = "LoginFragment"
}
}
Sie können TAG
auf oberster Ebene der Datei definieren, aber die
Datei kann auch eine große Anzahl von Variablen, Funktionen und Klassen enthalten.
die ebenfalls auf oberster Ebene definiert sind. Companion-Objekte helfen beim Verbinden
Variablen, Funktionen und der Klassendefinition, ohne sich auf
für eine bestimmte Instanz
dieser Klasse.
Property-Delegierung
Beim Initialisieren von Eigenschaften können Sie einige der gängigen Methoden von Android wiederholen.
Muster wie der Zugriff auf ein ViewModel
innerhalb einer Fragment
. Um übermäßige
duplizierten Codes können Sie die Syntax der Property-Delegierung von Kotlin verwenden.
private val viewModel: LoginViewModel by viewModels()
Die Property-Delegierung bietet eine gängige Implementierung, die Sie wiederverwenden können
in Ihrer App zu optimieren. Android KTX stellt Ihnen einige Property-Bevollmächtigte zur Verfügung.
Mit viewModels
wird beispielsweise ein ViewModel
abgerufen, das dem
(aktuell: Fragment
).
Bei der Property-Delegierung wird die Reflexion verwendet, was den Leistungsaufwand erhöht. Der Kompromiss besteht in einer prägnanten Syntax, die Entwicklungszeit spart.
Null-Zulässigkeit
Kotlin bietet strenge Regeln für die Null-Zulässigkeit, damit die Typsicherheit während der gesamten Dauer aufrechterhalten wird.
für Ihre App. In Kotlin dürfen Verweise auf Objekte keine Nullwerte enthalten:
Standardeinstellung. Wenn Sie einer Variablen einen Nullwert zuweisen möchten, müssen Sie eine Nullwerte zulässig deklarieren.
Variablentyp ändern, indem Sie ?
am Ende des Basistyps hinzufügen.
Der folgende Ausdruck ist beispielsweise in Kotlin nicht zulässig. name
ist vom Typ
String
und darf nicht Nullwerte enthalten:
val name: String = null
Um einen Nullwert zuzulassen, müssen Sie einen String
-Typ, für den Nullwerte zulässig sind, String?
verwenden:
Beispiel:
val name: String? = null
Interoperabilität
Die strengen Regeln von Kotlin machen Ihren Code sicherer und prägnanter. Diese Regeln sind niedriger
die Wahrscheinlichkeit eines NullPointerException
, der dazu führt, dass deine App
Abstürze. Außerdem reduzieren sie die Anzahl der Nullprüfungen, die Sie in Ihrem
Code.
Häufig müssen Sie beim Schreiben einer Android-App auch Nicht-Kotlin-Code aufrufen, da Die meisten Android-APIs sind in der Programmiersprache Java geschrieben.
Die Null-Zulässigkeit ist ein Schlüsselbereich, in dem sich Java und Kotlin im Verhalten unterscheiden. Java ist weniger mit der Syntax für Null-Zulässigkeit.
Die Klasse Account
hat beispielsweise einige Attribute, darunter ein String
-Element
mit dem Namen name
. In Java gibt es keine
Kotlin-Regeln für die Null-Zulässigkeit,
mithilfe optionaler Anmerkungen zur Null-Zulässigkeit
ob Sie einen Nullwert zuweisen können.
Da das Android-Framework hauptsächlich in Java geschrieben ist, dieses Szenario, wenn APIs ohne Anmerkungen zur Null-Zulässigkeit verwendet werden.
Plattformtypen
Wenn Sie mit Kotlin auf ein nicht annotiertes name
-Mitglied verweisen, das in einem
Java Account
, weiß der Compiler nicht, ob String
einer
String
oder String?
in Kotlin. Diese Ambiguität wird durch eine
Plattformtyp: String!
.
String!
hat für den Kotlin-Compiler keine besondere Bedeutung. String!
kann für
entweder einen String
- oder einen String?
-Wert. Mit dem Compiler können Sie den Wert
einen der beiden Typen. Beachten Sie, dass eine NullPointerException
ausgegeben wird, wenn Sie
den Typ als String
darstellen und einen Nullwert zuweisen.
Um dieses Problem zu beheben, sollten Sie beim Schreiben immer Annotationen zur Null-Zulässigkeit verwenden. Code in Java zu schreiben. Diese Annotationen sind sowohl für Java- als auch für Kotlin-Entwickler hilfreich.
Hier sehen Sie als Beispiel die Klasse Account
, wie sie in Java definiert ist:
public class Account implements Parcelable {
public final String name;
public final String type;
private final @Nullable String accessId;
...
}
Eine der Membervariablen, accessId
, ist mit @Nullable
annotiert:
, was darauf hinweist, dass sie einen Nullwert enthalten kann. Kotlin behandelt dann accessId
als String?
.
Mit der Annotation @NonNull
geben Sie an, dass eine Variable nie null sein darf:
public class Account implements Parcelable {
public final @NonNull String name;
...
}
In diesem Szenario gilt name
in Kotlin als eine String
, die keine Nullwerte zulässt.
Anmerkungen zur Null-Zulässigkeit sind in allen neuen Android-APIs und vielen bestehenden Android-APIs Viele Java-Bibliotheken haben Anmerkungen zur Null-Zulässigkeit hinzugefügt, um unterstützen sowohl Kotlin- als auch Java-Entwickler.
Umgang mit der Null-Zulässigkeit
Wenn Sie sich bei einem Java-Typ nicht sicher sind, sollten Sie davon ausgehen, dass er Nullwerte zulässt.
Beispiel: Das name
-Mitglied der Klasse Account
ist nicht annotiert.
sollte davon ausgehen, dass es sich um eine String
mit Nullwerten handelt.
Wenn Sie name
kürzen möchten, sodass sein Wert keine vorangestellten oder
Leerzeichen einfügen, können Sie die trim
-Funktion von Kotlin verwenden. Sie können einen
String?
. Eine dieser Möglichkeiten ist die Verwendung des Operators not-null
Assertion-Operator !!
aus, wie im folgenden Beispiel gezeigt:
val account = Account("name", "type")
val accountName = account.name!!.trim()
Der !!
-Operator behandelt alles auf seiner linken Seite als nicht null.
In diesem Fall behandeln Sie name
als String
ungleich null. Wenn das Ergebnis der
Ausdruck links null ist, löst Ihre App einen NullPointerException
aus.
Dieser Operator ist schnell und einfach, sollte aber sparsam verwendet werden,
fügen Sie Instanzen von NullPointerException
wieder in Ihren Code ein.
Sicherer ist die Verwendung des Safe-Call-Operators ?.
, wie in der
folgendes Beispiel:
val account = Account("name", "type")
val accountName = account.name?.trim()
Wenn name
mit dem Operator "safe-call" nicht null ist, wird das Ergebnis von
name?.trim()
ist ein Namenswert ohne voran- oder nachgestellte Leerzeichen. Wenn
name
ist null, dann ist das Ergebnis von name?.trim()
null
. Das bedeutet, dass
Ihre Anwendung darf beim Ausführen dieser Anweisung niemals NullPointerException
auslösen.
Die Funktion „Safe Call“ spart Ihnen zwar eine mögliche NullPointerException
,
wird ein Nullwert an die nächste Anweisung übergeben. Sie können stattdessen Nullwerte
Fälle sofort mithilfe eines Elvis-Operators (?:
) zu stellen, wie im Folgenden
Beispiel:
val account = Account("name", "type")
val accountName = account.name?.trim() ?: "Default name"
Wenn das Ergebnis des Ausdrucks auf der linken Seite des Elvis-Operators
null enthält, wird der Wert auf der rechten Seite accountName
zugewiesen. Dieses
ist nützlich, um einen Standardwert bereitzustellen, der ansonsten null wäre.
Sie können auch den Elvis-Operator verwenden, um eine Funktion frühzeitig zurückzugeben, wie gezeigt im folgenden Beispiel:
fun validateAccount(account: Account?) {
val accountName = account?.name?.trim() ?: "Default name"
// account cannot be null beyond this point
account ?: return
...
}
Änderungen bei der Android API
Android APIs werden immer besser für Kotlin geeignet. Viele der Android-Tools
enthalten, z. B. AppCompatActivity
und Fragment
,
Anmerkungen zur Null-Zulässigkeit. Bei bestimmten Aufrufen wie Fragment#getContext
mehr Kotlin-kompatible Alternativen.
Zum Beispiel ist der Zugriff auf das Context
einer Fragment
fast immer nicht null,
da die meisten Aufrufe in einer Fragment
stattfinden, während die Fragment
ist an Activity
angehängt (eine abgeleitete Klasse von Context
). Allerdings
Fragment#getContext
gibt nicht immer einen Wert ungleich Null zurück, da es
Szenarien, in denen Fragment
nicht an Activity
angehängt ist. Die Rückgabe
Für den Typ von Fragment#getContext
sind Nullwerte zulässig.
Da für das von Fragment#getContext
zurückgegebene Context
Nullwerte zulässig sind (und
als @Nullable annotiert sind, müssen Sie sie in Ihrem Kotlin-Code als Context?
behandeln.
Das bedeutet, dass einer der zuvor genannten Operatoren verwendet wird,
Null-Zulässigkeit, bevor auf ihre Attribute und Funktionen zugegriffen wird. Für einige von diesen
bietet Android alternative APIs, die diesen Komfort bieten.
Fragment#requireContext
gibt beispielsweise einen Context
-Wert zurück, der nicht
null ist, und wirft
eine IllegalStateException
, wenn sie aufgerufen wird, wenn ein Context
null sein würde. Auf diese Weise
können Sie die resultierende Context
als Nicht-Null behandeln, ohne
Safe-Call-Operatoren
oder Behelfslösungen.
Property-Initialisierung
Eigenschaften in Kotlin werden standardmäßig nicht initialisiert. Sie müssen initialisiert werden wenn ihre einschließende Klasse initialisiert wird.
Sie können Attribute auf verschiedene Arten initialisieren. Im folgenden Beispiel
zeigt, wie Sie eine index
-Variable initialisieren, indem Sie ihr einen Wert im
Klassendeklaration:
class LoginFragment : Fragment() {
val index: Int = 12
}
Diese Initialisierung kann auch in einem Initialisierungsblock definiert werden:
class LoginFragment : Fragment() {
val index: Int
init {
index = 12
}
}
In den Beispielen oben wird index
initialisiert, wenn LoginFragment
konstruiert sein.
Es kann jedoch sein, dass einige Eigenschaften während des Objekts
Bauarbeiten. Beispielsweise können Sie auf View
innerhalb einer
Fragment
, was bedeutet, dass das Layout zuerst aufgebläht werden muss. Inflation
tritt nicht auf, wenn eine Fragment
erstellt wird. Stattdessen wird er beim Aufrufen von
Fragment#onCreateView
Eine Möglichkeit, dieses Szenario zu umgehen, besteht darin, die Ansicht als Nullwerte zu deklarieren und so schnell wie möglich initialisieren, wie im folgenden Beispiel gezeigt:
class LoginFragment : Fragment() {
private var statusTextView: TextView? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
statusTextView = view.findViewById(R.id.status_text_view)
statusTextView?.setText(R.string.auth_failed)
}
}
Das funktioniert zwar wie erwartet, du musst aber jetzt die Null-Zulässigkeit von View
verwalten.
wenn Sie darauf verweisen. Besser ist es, lateinit
für View
zu verwenden
Initialisierung, wie im folgenden Beispiel gezeigt:
class LoginFragment : Fragment() {
private lateinit var statusTextView: TextView
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
statusTextView = view.findViewById(R.id.status_text_view)
statusTextView.setText(R.string.auth_failed)
}
}
Mit dem Schlüsselwort lateinit
können Sie die Initialisierung einer Property vermeiden, wenn ein
erstellt wird. Wenn vor der Initialisierung auf Ihre Property verwiesen wird,
Kotlin löst eine UninitializedPropertyAccessException
aus. Achten Sie daher darauf,
um Ihre Property so schnell wie möglich zu initialisieren.