Android KTX   Część Android Jetpack.

Android KTX to zestaw rozszerzeń Kotlin, które są częścią Android Jetpack i innych bibliotek Androida. Rozszerzenia KTX zapewniają zwięzły, idiomatyczny kod Kotlin dla Jetpack, platformy Android i innych interfejsów API. Aby to osiągnąć, rozszerzenia te wykorzystują kilka funkcji języka Kotlin, w tym:

  • funkcje rozszerzające,
  • właściwości rozszerzające,
  • lambdy,
  • nazwane parametry,
  • wartości domyślne parametrów,
  • współprogramy.

Na przykład podczas pracy z SharedPreferences musisz utworzyć edytor zanim będziesz mieć możliwość modyfikowania danych preferencji. Po zakończeniu edycji musisz też zastosować lub zatwierdzić te zmiany, jak pokazano w tym przykładzie:

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

Lambdy Kotlin doskonale nadają się do tego przypadku użycia. Umożliwiają one bardziej zwięzłe podejście, ponieważ pozwalają przekazać blok kodu do wykonania po utworzeniu edytora, a następnie wykonać kod i zastosować zmiany atomowo za pomocą interfejsu API SharedPreferences.

Oto przykład jednej z funkcji Android KTX Core, SharedPreferences.edit, która dodaje funkcję edycji do SharedPreferences. Ta funkcja przyjmuje jako pierwszy argument opcjonalną flagę boolean, która wskazuje, czy zmiany mają zostać zatwierdzone, czy zastosowane. Otrzymuje też działanie, które ma zostać wykonane w edytorze SharedPreferences, w postaci lambdy.

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

Wywołujący może wybrać, czy zmiany mają zostać zatwierdzone, czy zastosowane. Lambda action jest anonimową funkcją rozszerzającą w SharedPreferences.Editor, która zwraca Unit, co wskazuje jej sygnatura. Dlatego w bloku możesz wykonywać pracę bezpośrednio w SharedPreferences.Editor.

Na koniec sygnatura SharedPreferences.edit() zawiera słowo kluczowe inline. To słowo kluczowe informuje kompilator Kotlin, że powinien kopiować i wklejać (lub wstawiać) skompilowany kod bajtowy funkcji za każdym razem, gdy funkcja jest używana. Pozwala to uniknąć obciążenia związanego z tworzeniem nowej klasy dla każdej action za każdym razem, gdy ta funkcja jest wywoływana.

Ten wzorzec przekazywania kodu za pomocą lambd, stosowania rozsądnych wartości domyślnych, które można zastąpić, i dodawania tych zachowań do istniejących interfejsów API za pomocą funkcji rozszerzających inline jest typowy dla ulepszeń zapewnianych przez bibliotekę Android KTX.

Używanie Android KTX w projekcie

Aby zacząć korzystać z Android KTX, dodaj tę zależność do pliku build.gradle projektu:

Dynamiczny

repositories {
    google()
}

Kotlin

repositories {
    google()
}

Moduły AndroidX

Android KTX jest podzielony na moduły, z których każdy zawiera co najmniej 1 pakiet.

W pliku build.gradle aplikacji musisz uwzględnić zależność dla każdego artefaktu modułu. Pamiętaj, aby dołączyć do artefaktu numer wersji. Najnowsze numery wersji znajdziesz w odpowiedniej sekcji tego artykułu.

Android KTX zawiera pojedynczy moduł podstawowy, który udostępnia rozszerzenia Kotlin dla typowych interfejsów API platformy, oraz kilka rozszerzeń specyficznych dla domeny.

Z wyjątkiem modułu podstawowego wszystkie artefakty modułu KTX zastępują podstawową zależność Java w pliku build.gradle. Możesz na przykład zastąpić zależność androidx.fragment:fragment zależnością androidx.fragment:fragment-ktx. Ta składnia ułatwia zarządzanie wersjami i nie dodaje dodatkowych wymagań dotyczących deklaracji zależności.

Podstawowy KTX

Moduł Core KTX udostępnia rozszerzenia dla typowych bibliotek, które są częścią platformy Android. Biblioteki te nie mają zależności opartych na Javie, które trzeba dodać do build.gradle.

Aby uwzględnić ten moduł, dodaj do pliku build.gradle aplikacji te wiersze:

Groovy

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

Kotlin

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

Oto lista pakietów zawartych w module Core KTX:

Kolekcja KTX

Rozszerzenia kolekcji zawierają funkcje narzędziowe do pracy z wydajnymi bibliotekami kolekcji Androida, w tym ArrayMap, LongSparseArray, LruCache i innymi.

Aby użyć tego modułu, dodaj do pliku build.gradle aplikacji te wiersze:

Groovy

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

Kotlin

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

Rozszerzenia kolekcji wykorzystują przeciążanie operatorów Kotlin, aby uprościć takie czynności jak łączenie kolekcji, jak pokazano w tym przykładzie:

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

Fragment KTX

Moduł Fragment KTX udostępnia szereg rozszerzeń, które upraszczają interfejs API fragmentu.

Aby uwzględnić ten moduł, dodaj do pliku build.gradle aplikacji te wiersze:

Odlotowe

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

Kotlin

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

Dzięki modułowi Fragment KTX możesz uprościć transakcje fragmentów za pomocą lambd, na przykład:

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

Możesz też powiązać się z ViewModel w 1 wierszu, używając delegatów właściwości viewModels i activityViewModels:

// 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>()

Cykl życia KTX

Cykl życia KTX definiuje LifecycleScope dla każdego Lifecycle obiektu. Każdy współprogram uruchomiony w tym zakresie jest anulowany, gdy Lifecycle zostanie zniszczony. Dostęp do CoroutineScope w Lifecycle możesz uzyskać za pomocą właściwości lifecycle.coroutineScope lub lifecycleOwner.lifecycleScope.

Aby uwzględnić ten moduł, dodaj do pliku build.gradle aplikacji te wiersze:

Groovy

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

Kotlin

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

Ten przykład pokazuje, jak używać lifecycleOwner.lifecycleScope do asynchronicznego tworzenia wstępnie obliczonego tekstu:

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

Podczas korzystania z LiveData może być konieczne asynchroniczne obliczanie wartości. Możesz na przykład pobrać preferencje użytkownika i wyświetlić je w interfejsie. W takich przypadkach LiveData KTX udostępnia funkcję tworzenia liveData, która wywołuje funkcję suspend i udostępnia wynik jako obiekt LiveData.

Aby uwzględnić ten moduł, dodaj do pliku build.gradle aplikacji te wiersze:

Groovy

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

Kotlin

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

W tym przykładzie loadUser() jest funkcją zawieszającą zadeklarowaną w innym miejscu. Możesz użyć funkcji tworzenia liveData, aby asynchronicznie wywołać loadUser(), a następnie użyć emit(), aby wyemitować wynik:

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

Więcej informacji o używaniu współprogramów z LiveData znajdziesz w artykule Używanie współprogramów Kotlin z komponentami architektury.

Każdy komponent biblioteki nawigacji ma własną wersję KTX, która dostosowuje interfejs API, aby był bardziej zwięzły i idiomatyczny dla Kotlin.

Aby uwzględnić te moduły, dodaj do pliku build.gradle aplikacji te wiersze:

Groovy

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

Kotlin

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

Użyj funkcji rozszerzających i delegowania właściwości, aby uzyskać dostęp do argumentów miejsca docelowego i przejść do miejsc docelowych, jak pokazano w tym przykładzie:

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

}

Paleta KTX

Moduł Palette KTX oferuje idiomatyczną obsługę Kotlin do pracy z paletami kolorów.

Aby użyć tego modułu, dodaj do pliku build.gradle aplikacji te wiersze:

Odlotowe

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

Kotlin

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

Na przykład podczas pracy z instancją Palette możesz pobrać próbkę selected dla danego target za pomocą operatora get ([ ]):

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

Strumienie reaktywne KTX

Moduł Reactive Streams KTX umożliwia utworzenie obserwowalnego strumienia LiveData z wydawcy ReactiveStreams.

Aby uwzględnić ten moduł, dodaj do pliku build.gradle aplikacji te wiersze:

Groovy

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

Kotlin

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

Załóżmy na przykład, że masz bazę danych z krótką listą użytkowników. W aplikacji wczytujesz bazę danych do pamięci, a następnie wyświetlasz dane użytkownika w interfejsie. Aby to osiągnąć, możesz użyć RxJava. Komponent Jetpack Room może pobrać listę użytkowników jako Flowable. W tym przypadku musisz też zarządzać subskrypcją wydawcy Rx przez cały okres istnienia fragmentu lub aktywności.

Dzięki LiveDataReactiveStreams możesz jednak korzystać z RxJava i jego bogatego zestawu operatorów oraz funkcji planowania pracy, a jednocześnie pracować z prostotą LiveData, jak pokazano w tym przykładzie:

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

Room KTX

Rozszerzenia Room dodają obsługę współprogramów do transakcji bazy danych.

Aby użyć tego modułu, dodaj do pliku build.gradle aplikacji te wiersze:

Groovy

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

Kotlin

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

Oto kilka przykładów, w których Room używa teraz współprogramów. Pierwszy przykład używa funkcji suspend, aby zwrócić listę obiektów User, a drugi wykorzystuje Flow Kotlin do asynchronicznego zwracania listy User. Pamiętaj, że podczas korzystania z Flow otrzymujesz też powiadomienia o wszelkich zmianach w tabelach, o które wysyłasz zapytania.

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

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

SQLite KTX

Rozszerzenia SQLite otaczają kod związany z SQL transakcjami, eliminując wiele powtarzalnego kodu.

Aby użyć tego modułu, dodaj do pliku build.gradle aplikacji te wiersze:

Groovy

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

Kotlin

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

Oto przykład użycia rozszerzenia transaction do wykonania transakcji bazy danych:

db.transaction {
    // insert data
}

ViewModel KTX

Biblioteka ViewModel KTX udostępnia funkcję viewModelScope(), która ułatwia uruchamianie współprogramów z ViewModel. CoroutineScope jest powiązany z Dispatchers.Main i jest automatycznie anulowany , gdy ViewModel zostanie wyczyszczony. Zamiast tworzyć nowy zakres dla każdego ViewModel, możesz użyć viewModelScope().

Aby uwzględnić ten moduł, dodaj do pliku build.gradle aplikacji te wiersze:

Groovy

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

Kotlin

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

Na przykład ta funkcja viewModelScope() uruchamia współprogram, który wysyła żądanie sieciowe w wątku w tle. Biblioteka obsługuje całą konfigurację i odpowiednie czyszczenie zakresu:

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 zapewnia pełną obsługę współprogramów.

Aby uwzględnić ten moduł, dodaj do pliku build.gradle aplikacji te wiersze:

Odlotowe

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

Kotlin

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

Zamiast rozszerzać Worker, możesz teraz rozszerzyć CoroutineWorker, który ma nieco inny interfejs API. Jeśli na przykład chcesz utworzyć prosty CoroutineWorker do wykonywania operacji sieciowych, możesz to zrobić w ten sposób:

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

Więcej informacji o używaniu CoroutineWorker znajdziesz w artykule Wątki w CoroutineWorker.

WorkManager KTX dodaje też funkcje rozszerzające do Operations i ListenableFutures, aby zawiesić bieżący współprogram.

Oto przykład, który zawiesza Operation zwracany przez enqueue():

// Inside of a coroutine...

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

// Resume after work completes...

Inne moduły KTX

Możesz też uwzględnić dodatkowe moduły KTX, które znajdują się poza AndroidX.

Firebase KTX

Niektóre pakiety Firebase SDK na Androida mają biblioteki rozszerzeń Kotlin, które umożliwiają pisanie idiomatycznego kodu Kotlin podczas korzystania z Firebase w aplikacji. Więcej informacji znajdziesz w tych artykułach:

Google Maps Platform KTX

Dostępne są rozszerzenia KTX dla pakietów Google Maps Platform SDK na Androida, które umożliwiają korzystanie z kilku funkcji języka Kotlin, takich jak funkcje rozszerzające, nazwane parametry i argumenty domyślne, deklaracje destrukcyjne i współprogramy. Więcej informacji znajdziesz w tych artykułach:

Play Core KTX

Play Core KTX dodaje obsługę współprogramów Kotlin w przypadku jednorazowych żądań i Flow do monitorowania aktualizacji stanu przez dodanie funkcji rozszerzających do SplitInstallManager i AppUpdateManager w podstawowej bibliotece Play.

Aby uwzględnić ten moduł, dodaj do pliku build.gradle aplikacji te wiersze:

Groovy

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

Kotlin

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

Oto przykład Flow monitorującego stan:

// 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()
    }
}

Więcej informacji

Więcej informacji o Android KTX znajdziesz w filmie DevBytes.

Aby zgłosić problem lub zaproponować funkcję, użyj problem trackera Android KTX.