Android KTX Teil von Android Jetpack

Android KTX umfasst eine Reihe von Kotlin-Erweiterungen, die in Android Jetpack und anderen Android-Bibliotheken enthalten sind. KTX-Erweiterungen bieten prägnanten, idiomatischen Kotlin-Code für Jetpack, die Android-Plattform und andere APIs. Dazu nutzen diese Erweiterungen mehrere Kotlin-Sprachfunktionen, darunter:

  • Erweiterungsfunktionen
  • Erweiterungseigenschaften
  • Lambdas
  • Benannte Parameter
  • Standardwerte der Parameter
  • Koroutinen

Wenn Sie beispielsweise mit SharedPreferences arbeiten, müssen Sie einen Editor erstellen, bevor Sie Änderungen an den Einstellungsdaten vornehmen können. Sie müssen diese Änderungen auch anwenden oder einen Commit durchführen, wenn Sie mit der Bearbeitung fertig sind, wie im folgenden Beispiel gezeigt:

sharedPreferences
        .edit()  // create an Editor
        .putBoolean("key", value)
        .apply() // write to disk asynchronously

Kotlin-Lambdas sind für diesen Anwendungsfall perfekt geeignet. Sie ermöglichen einen präziseren Ansatz, indem Sie einen Codeblock übergeben, der nach dem Erstellen des Editors ausgeführt werden soll, den Code ausführen lassen und dann die Änderungen in kleinstmöglichen Schritten von der SharedPreferences API anwenden lassen.

Hier ist ein Beispiel für eine der Android KTX Core-Funktionen, SharedPreferences.edit, die eine Bearbeitungsfunktion zu SharedPreferences hinzufügt. Diese Funktion verwendet ein optionales boolean-Flag als erstes Argument, das angibt, ob die Änderungen per Commit übergeben oder angewendet werden sollen. Außerdem erhält sie eine Aktion, die im SharedPreferences-Editor in Form einer Lambda-Funktion ausgeführt werden kann.

// SharedPreferences.edit extension function signature from Android KTX - Core
// inline fun SharedPreferences.edit(
//         commit: Boolean = false,
//         action: SharedPreferences.Editor.() -> Unit)

// Commit a new value asynchronously
sharedPreferences.edit { putBoolean("key", value) }

// Commit a new value synchronously
sharedPreferences.edit(commit = true) { putBoolean("key", value) }

Der Aufrufer kann auswählen, ob ein Commit durchgeführt oder die Änderungen angewendet werden sollen. Das Lambda action ist selbst eine anonyme Erweiterungsfunktion für SharedPreferences.Editor, die, wie durch seine Signatur angegeben, Unit zurückgibt. Deshalb können Sie innerhalb des Blocks die Arbeit direkt auf SharedPreferences.Editor ausführen.

Die SharedPreferences.edit()-Signatur enthält schließlich das Schlüsselwort inline. Dieses Schlüsselwort teilt dem Kotlin-Compiler mit, dass er den kompilierten Bytecode für die Funktion bei jeder Verwendung der Funktion kopieren und einfügen (oder inline) einfügen soll. Dadurch wird der Aufwand vermieden, bei jedem Aufruf dieser Funktion für jede action eine neue Klasse zu instanziieren.

Dieses Muster zum Übergeben von Code mithilfe von Lambdas, Anwenden sinnvoller Standardwerte, die überschrieben werden können, und Hinzufügen dieser Verhaltensweisen zu vorhandenen APIs mithilfe von inline-Erweiterungsfunktionen ist typisch für die Verbesserungen, die in der Android KTX-Bibliothek bereitgestellt werden.

Android KTX in Ihrem Projekt verwenden

Damit Sie Android KTX verwenden können, fügen Sie der Datei build.gradle Ihres Projekts die folgende Abhängigkeit hinzu:

Cool

repositories {
    google()
}

Kotlin

repositories {
    google()
}

AndroidX-Module

Android KTX ist in Modulen organisiert, wobei jedes Modul ein oder mehrere Pakete enthält.

Sie müssen für jedes Modulartefakt in der Datei build.gradle Ihrer Anwendung eine Abhängigkeit einfügen. Denken Sie daran, dem Artefakt die Versionsnummer anzuhängen. Sie finden die neuesten Versionsnummern im entsprechenden Abschnitt zu jedem Artefakt in diesem Thema.

Android KTX enthält ein einzelnes Kernmodul, das Kotlin-Erweiterungen für gängige Framework-APIs und mehrere domainspezifische Erweiterungen bietet.

Mit Ausnahme des Kernmoduls ersetzen alle KTX-Modulartefakte die zugrunde liegende Java-Abhängigkeit in Ihrer build.gradle-Datei. Sie können beispielsweise eine androidx.fragment:fragment-Abhängigkeit durch androidx.fragment:fragment-ktx ersetzen. Diese Syntax erleichtert die Versionsverwaltung und sorgt nicht für zusätzliche Anforderungen an die Abhängigkeitsdeklaration.

Core KTX

Das Core KTX-Modul bietet Erweiterungen für gängige Bibliotheken, die Teil des Android-Frameworks sind. Diese Bibliotheken haben keine Java-basierten Abhängigkeiten, die Sie build.gradle hinzufügen müssen.

Wenn Sie dieses Modul verwenden möchten, fügen Sie der Datei build.gradle Ihrer App Folgendes hinzu:

Groovig

dependencies {
    implementation "androidx.core:core-ktx:1.13.1"
}

Kotlin

dependencies {
    implementation("androidx.core:core-ktx:1.13.1")
}

Hier ist eine Liste der Pakete, die im Core KTX-Modul enthalten sind:

Sammlung KTX

Sammlungserweiterungen enthalten Dienstfunktionen für die Arbeit mit den speichereffizienten Sammlungsbibliotheken von Android, darunter ArrayMap, LongSparseArray und LruCache.

Fügen Sie der Datei build.gradle Ihrer App Folgendes hinzu, um dieses Modul zu verwenden:

Groovig

dependencies {
    implementation "androidx.collection:collection-ktx:1.4.1"
}

Kotlin

dependencies {
    implementation("androidx.collection:collection-ktx:1.4.1")
}

Sammlungserweiterungen nutzen die Überlastung des Kotlin-Operators, um Dinge wie die Sammlungsverkettung zu vereinfachen, wie im folgenden Beispiel gezeigt:

// Combine 2 ArraySets into 1.
val combinedArraySet = arraySetOf(1, 2, 3) + arraySetOf(4, 5, 6)

// Combine with numbers to create a new sets.
val newArraySet = combinedArraySet + 7 + 8

KTX-Fragment

Das Fragment KTX-Modul bietet eine Reihe von Erweiterungen zur Vereinfachung der Fragment API.

Wenn Sie dieses Modul verwenden möchten, fügen Sie der Datei build.gradle Ihrer App Folgendes hinzu:

Groovig

dependencies {
    implementation "androidx.fragment:fragment-ktx:1.8.1"
}

Kotlin

dependencies {
    implementation("androidx.fragment:fragment-ktx:1.8.1")
}

Mit dem Fragment KTX-Modul können Sie Fragmenttransaktionen mit Lambdas vereinfachen. Beispiel:

fragmentManager().commit {
   addToBackStack("...")
   setCustomAnimations(
           R.anim.enter_anim,
           R.anim.exit_anim)
   add(fragment, "...")
}

Sie können eine Bindung an eine ViewModel in einer Zeile auch mithilfe der Attributdelegierten viewModels und activityViewModels vornehmen:

// Get a reference to the ViewModel scoped to this Fragment
val viewModel by viewModels<MyViewModel>()

// Get a reference to the ViewModel scoped to its Activity
val viewModel by activityViewModels<MyViewModel>()

Lifecycle-KTX

Lifecycle-KTX definiert eine LifecycleScope für jedes Lifecycle-Objekt. Jede in diesem Bereich gestartete Koroutine wird abgebrochen, wenn die Lifecycle gelöscht wird. Auf den CoroutineScope der Lifecycle können Sie über die Attribute lifecycle.coroutineScope oder lifecycleOwner.lifecycleScope zugreifen.

Wenn Sie dieses Modul verwenden möchten, fügen Sie der Datei build.gradle Ihrer App Folgendes hinzu:

Groovig

dependencies {
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.8.3"
}

Kotlin

dependencies {
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.3")
}

Das folgende Beispiel zeigt, wie lifecycleOwner.lifecycleScope verwendet wird, um vorab berechneten Text asynchron zu erstellen:

class MyFragment: Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewLifecycleOwner.lifecycleScope.launch {
            val params = TextViewCompat.getTextMetricsParams(textView)
            val precomputedText = withContext(Dispatchers.Default) {
                PrecomputedTextCompat.create(longTextContent, params)
            }
            TextViewCompat.setPrecomputedText(textView, precomputedText)
        }
    }
}

LiveData KTX

Bei der Verwendung von LiveData müssen Sie die Werte möglicherweise asynchron berechnen. Sie haben beispielsweise die Möglichkeit, die Einstellungen eines Nutzers abzurufen und Ihrer UI bereitzustellen. In diesen Fällen bietet LiveData KTX eine liveData-Builder-Funktion, die eine suspend-Funktion aufruft und das Ergebnis als LiveData-Objekt bereitstellt.

Wenn Sie dieses Modul verwenden möchten, fügen Sie der Datei build.gradle Ihrer App Folgendes hinzu:

Groovig

dependencies {
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.8.3"
}

Kotlin

dependencies {
    implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.8.3")
}

Im folgenden Beispiel ist loadUser() eine an anderer Stelle deklarierte Sperrfunktion. Sie können die Builder-Funktion liveData verwenden, um loadUser() asynchron aufzurufen, und dann emit() verwenden, um das Ergebnis auszugeben:

val user: LiveData<User> = liveData {
    val data = database.loadUser() // loadUser is a suspend function.
    emit(data)
}

Weitere Informationen zur Verwendung von Koroutinen mit LiveData finden Sie unter Kotlin-Koroutinen mit Architekturkomponenten verwenden.

Jede Komponente der Navigationsbibliothek hat eine eigene KTX-Version, die die API so anpasst, dass sie kürzer und idiomatischer ist.

Wenn Sie diese Module einbinden möchten, fügen Sie der Datei build.gradle Ihrer App Folgendes hinzu:

Groovig

dependencies {
    implementation "androidx.navigation:navigation-runtime-ktx:2.7.7"
    implementation "androidx.navigation:navigation-fragment-ktx:2.7.7"
    implementation "androidx.navigation:navigation-ui-ktx:2.7.7"
}

Kotlin

dependencies {
    implementation("androidx.navigation:navigation-runtime-ktx:2.7.7")
    implementation("androidx.navigation:navigation-fragment-ktx:2.7.7")
    implementation("androidx.navigation:navigation-ui-ktx:2.7.7")
}

Verwenden Sie die Erweiterungsfunktionen und die Attributdelegierung, um auf Zielargumente zuzugreifen und Ziele aufzurufen, wie im folgenden Beispiel gezeigt:

class MyDestination : Fragment() {

    // Type-safe arguments are accessed from the bundle.
    val args by navArgs<MyDestinationArgs>()

    ...
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        view.findViewById<Button>(R.id.next)
            .setOnClickListener {
                // Fragment extension added to retrieve a NavController from
                // any destination.
                findNavController().navigate(R.id.action_to_next_destination)
            }
     }
     ...

}

Palette KTX

Das Palette KTX-Modul bietet idiomatische Kotlin-Unterstützung für die Arbeit mit Farbvorlagen.

Fügen Sie der Datei build.gradle Ihrer App Folgendes hinzu, um dieses Modul zu verwenden:

Groovig

dependencies {
    implementation "androidx.palette:palette-ktx:1.0.0"
}

Kotlin

dependencies {
    implementation("androidx.palette:palette-ktx:1.0.0")
}

Wenn Sie beispielsweise mit einer Palette-Instanz arbeiten, können Sie das selected-Muster für einen bestimmten target mit dem get-Operator ([ ]) abrufen:

val palette = Palette.from(bitmap).generate()
val swatch = palette[target]

Reaktive Streams KTX

Mit dem KTX-Modul von Reactive Streams können Sie einen beobachtbaren LiveData-Stream von einem ReactiveStreams-Publisher erstellen.

Wenn Sie dieses Modul verwenden möchten, fügen Sie der Datei build.gradle Ihrer App Folgendes hinzu:

Groovig

dependencies {
    implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:2.8.3"
}

Kotlin

dependencies {
    implementation("androidx.lifecycle:lifecycle-reactivestreams-ktx:2.8.3")
}

Nehmen wir als Beispiel an, dass es sich um eine Datenbank mit einer kleinen Liste von Nutzern handelt. In Ihrer Anwendung laden Sie die Datenbank in den Arbeitsspeicher und zeigen dann Nutzerdaten in Ihrer UI an. Dazu können Sie RxJava verwenden. Die Jetpack-Komponente Room kann die Nutzerliste als Flowable abrufen. In diesem Szenario müssen Sie auch das Rx-Publisher-Abo für die gesamte Lebensdauer des Fragments oder Ihrer Aktivität verwalten.

Mit LiveDataReactiveStreams können Sie jedoch von RxJava und seinen umfangreichen Operatoren und Funktionen zur Arbeitsplanung profitieren und gleichzeitig mit der Einfachheit von LiveData arbeiten, wie im folgenden Beispiel gezeigt:

val fun getUsersLiveData() : LiveData<List<User>> {
    val users: Flowable<List<User>> = dao.findUsers()
    return LiveDataReactiveStreams.fromPublisher(users)
}

Raum KTX

Raumerweiterungen unterstützen Koroutinen für Datenbanktransaktionen.

Fügen Sie der Datei build.gradle Ihrer App Folgendes hinzu, um dieses Modul zu verwenden:

Cool

dependencies {
    implementation "androidx.room:room-ktx:2.6.1"
}

Kotlin

dependencies {
    implementation("androidx.room:room-ktx:2.6.1")
}

Hier sind einige Beispiele, in denen in Room Koroutinen verwendet werden. Im ersten Beispiel wird eine suspend-Funktion verwendet, um eine Liste von User-Objekten zurückzugeben. Im zweiten Beispiel wird Flow von Kotlin verwendet, um die User-Liste asynchron zurückzugeben. Bei Verwendung von Flow werden Sie auch über Änderungen an den Tabellen benachrichtigt, die Sie abfragen.

@Query("SELECT * FROM Users")
suspend fun getUsers(): List<User>

@Query("SELECT * FROM Users")
fun getUsers(): Flow<List<User>>

SQLite KTX

SQLite-Erweiterungen verpacken SQL-bezogenen Code in Transaktionen und eliminieren daher eine Menge Boilerplate-Code.

Fügen Sie der Datei build.gradle Ihrer App Folgendes hinzu, um dieses Modul zu verwenden:

Groovig

dependencies {
    implementation "androidx.sqlite:sqlite-ktx:2.4.0"
}

Kotlin

dependencies {
    implementation("androidx.sqlite:sqlite-ktx:2.4.0")
}

Hier ist ein Beispiel für die Verwendung der Erweiterung transaction zum Ausführen einer Datenbanktransaktion:

db.transaction {
    // insert data
}

ViewModel KTX

Die ViewModel KTX-Bibliothek bietet eine viewModelScope()-Funktion, mit der sich Coroutinen ganz einfach über ViewModel starten lassen. CoroutineScope ist an Dispatchers.Main gebunden und wird automatisch abgebrochen, wenn ViewModel gelöscht wird. Sie können viewModelScope() verwenden, anstatt für jede ViewModel einen neuen Bereich zu erstellen.

Wenn Sie dieses Modul verwenden möchten, fügen Sie der Datei build.gradle Ihrer App Folgendes hinzu:

Groovig

dependencies {
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.3"
}

Kotlin

dependencies {
    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.3")
}

Die folgende viewModelScope()-Funktion startet beispielsweise eine Koroutine, die eine Netzwerkanfrage in einem Hintergrundthread stellt. Die Bibliothek übernimmt die gesamte Einrichtung und das Löschen des entsprechenden Bereichs:

class MainViewModel : ViewModel() {
    // Make a network request without blocking the UI thread
    private fun makeNetworkRequest() {
        // launch a coroutine in viewModelScope
        viewModelScope.launch  {
            remoteApi.slowFetch()
            ...
        }
    }

    // No need to override onCleared()
}

WorkManager KTX

WorkManager KTX bietet erstklassige Unterstützung für Koroutinen.

Wenn Sie dieses Modul verwenden möchten, fügen Sie der Datei build.gradle Ihrer App Folgendes hinzu:

Groovig

dependencies {
    implementation "androidx.work:work-runtime-ktx:2.9.0"
}

Kotlin

dependencies {
    implementation("androidx.work:work-runtime-ktx:2.9.0")
}

Anstatt Worker zu erweitern, können Sie jetzt CoroutineWorker erweitern. Diese hat eine etwas andere API. Wenn Sie beispielsweise eine einfache CoroutineWorker erstellen möchten, um einige Netzwerkvorgänge auszuführen, können Sie so vorgehen:

class CoroutineDownloadWorker(context: Context, params: WorkerParameters)
        : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result = coroutineScope {
        val jobs = (0 until 100).map {
            async {
                downloadSynchronously("https://www.google.com")
            }
        }

        // awaitAll will throw an exception if a download fails, which
        // CoroutineWorker will treat as a failure
        jobs.awaitAll()
        Result.success()
    }
}

Weitere Informationen zur Verwendung von CoroutineWorker finden Sie unter Threading in CoroutineWorker.

WorkManager KTX fügt Operations und ListenableFutures außerdem Erweiterungsfunktionen hinzu, um die aktuelle Koroutine auszusetzen.

Im folgenden Beispiel wird der Operation gesperrt, der von enqueue() zurückgegeben wird:

// Inside of a coroutine...

// Run async operation and suspend until completed.
WorkManager.getInstance()
        .beginWith(longWorkRequest)
        .enqueue().await()

// Resume after work completes...

Weitere KTX-Module

Sie können auch zusätzliche KTX-Module einbinden, die nicht in AndroidX vorhanden sind.

Firebase KTX

Einige der Firebase SDKs für Android haben Kotlin-Erweiterungsbibliotheken, mit denen Sie idiomatischen Kotlin-Code schreiben können, wenn Sie Firebase in Ihrer App verwenden. Weitere Informationen finden Sie in den folgenden Themen:

Google Maps Platform KTX

Es gibt KTX-Erweiterungen für Google Maps Platform Android SDKs, mit denen Sie verschiedene Kotlin-Sprachfunktionen wie Erweiterungsfunktionen, benannte Parameter und Standardargumente, destruktive Deklarationen und Koroutinen nutzen können. Weitere Informationen finden Sie in den folgenden Themen:

Play Core KTX

Play Core KTX unterstützt Kotlin-Koroutinen für One-Shot-Anfragen und Flow für das Monitoring von Statusaktualisierungen. Dazu werden Erweiterungsfunktionen zu SplitInstallManager und AppUpdateManager in der Play Core-Bibliothek hinzugefügt.

Wenn Sie dieses Modul verwenden möchten, fügen Sie der Datei build.gradle Ihrer App Folgendes hinzu:

Cool

dependencies {
    implementation "com.google.android.play:core-ktx:1.8.1"
}

Kotlin

dependencies {
    implementation("com.google.android.play:core-ktx:1.8.1")
}

Hier ein Beispiel für eine Statusüberwachung Flow:

// Inside of a coroutine...

// Request in-app update status updates.
manager.requestUpdateFlow().collect { updateResult ->
    when (updateResult) {
        is AppUpdateResult.Available -> TODO()
        is AppUpdateResult.InProgress -> TODO()
        is AppUpdateResult.Downloaded -> TODO()
        AppUpdateResult.NotAvailable -> TODO()
    }
}

Weitere Informationen

Weitere Informationen zu Android KTX findest du im DevBytes-Video.

Verwenden Sie die Android KTX-Problemverfolgung, um ein Problem zu melden oder eine Funktion vorzuschlagen.