Android KTX Partie intégrante d'Android Jetpack.

Android KTX est un ensemble d'extensions Kotlin incluses dans Jetpack et d'autres bibliothèques Android. Les extensions KTX fournissent du code Kotlin idiomatique et concis à Jetpack, à la plate-forme Android et à d'autres API. Pour ce faire, elles s'appuient sur plusieurs fonctionnalités du langage Kotlin, y compris les suivantes :

  • Fonctions d'extension
  • Propriétés d'extension
  • Lambdas
  • Paramètres nommés
  • Valeurs par défaut des paramètres
  • Coroutines

Par exemple, lorsque vous utilisez SharedPreferences, vous devez créer un éditeur avant de pouvoir apporter des modifications aux données de préférence. Une fois ces modifications terminées, vous devez également les appliquer ou les valider, comme illustré dans l'exemple suivant :

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

Les lambdas Kotlin conviennent parfaitement à ce cas d'utilisation. Ils vous permettent d'adopter une approche plus concise en transmettant un bloc de code à exécuter après la création de l'éditeur, en laissant le code s'exécuter, puis en laissant l'API SharedPreferences appliquer les modifications de manière atomique.

Voici un exemple de l'une des fonctions principales Android KTX, SharedPreferences.edit, qui ajoute une fonction de modification à SharedPreferences. Cette fonction utilise un indicateur boolean facultatif comme premier argument qui indique s'il faut valider ou appliquer les modifications. Il reçoit également une action à effectuer sur l'éditeur SharedPreferences sous la forme d'un lambda.

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

L'appelant peut choisir de valider ou d'appliquer les modifications. L'action est une fonction d'extension anonyme sur le SharedPreferences.Editor qui renvoie Unit, comme indiqué par sa signature. C'est pourquoi, à l'intérieur du bloc, vous pouvez effectuer la tâche directement sur le SharedPreferences.Editor.

Enfin, la signature SharedPreferences.edit() contient le mot clé inline. Celui-ci indique au compilateur Kotlin qu'il doit copier et coller (ou intégrer) le bytecode compilé pour la fonction chaque fois qu'elle est utilisée. Cela évite d'avoir à instancier une nouvelle classe pour chaque action à chaque fois que cette fonction est appelée.

Ce modèle consistant à transmettre du code à l'aide de lambdas, à appliquer des valeurs par défaut logiques pouvant être remplacées et à ajouter ces comportements aux API existantes à l'aide de fonctions d'extension inline est représentatif des améliorations apportées par la bibliothèque KTX d'Android.

Utiliser Android KTX dans votre projet

Pour commencer à utiliser Android KTX, ajoutez la dépendance suivante au fichier build.gradle de votre projet :

Groovy

repositories {
    google()
}

Kotlin

repositories {
    google()
}

Modules AndroidX

Android KTX est organisé en modules, chacun contenant un ou plusieurs packages.

Vous devez inclure une dépendance pour chaque artefact de module dans le fichier build.gradle de votre application. N'oubliez pas d'ajouter le numéro de version à chaque artefact. Vous trouverez les derniers numéros de version dans la section correspondante de chaque artefact dans cette rubrique.

Android KTX contient un module à cœur unique qui fournit des extensions Kotlin pour les API courantes du framework et plusieurs extensions spécifiques à un domaine.

À l'exception du module principal, tous les artefacts des modules KTX remplacent la dépendance Java sous-jacente de votre fichier build.gradle. Par exemple, vous pouvez remplacer une dépendance androidx.fragment:fragment par androidx.fragment:fragment-ktx. Cette syntaxe permet de mieux gérer les versions et n'ajoute aucune exigence supplémentaire en matière de déclaration des dépendances.

Core KTX

Le module Core KTX fournit des extensions pour les bibliothèques courantes qui font partie du framework Android. Ces bibliothèques ne comportent pas de dépendances Java que vous devez ajouter à build.gradle.

Pour inclure ce module, ajoutez les le code suivant au fichier build.gradle de votre application :

Groovy

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

Kotlin

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

Voici la liste des packages contenus dans le module Core KTX :

Collection KTX

Les extensions Collection contiennent des fonctions utilitaires permettant de travailler avec les bibliothèques de collection à mémoire optimisée d'Android, par exemple ArrayMap, LongSparseArray et LruCache.

Pour utiliser ce module, ajoutez le code suivant au fichier build.gradle de votre application :

Groovy

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

Kotlin

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

Les extensions Collection exploitent la surcharge de l'opérateur de Kotlin pour simplifier des éléments tels que la concaténation des collections, comme illustré dans l'exemple suivant :

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

Le module Fragment KTX fournit un certain nombre d'extensions pour simplifier l'API Fragment.

Pour inclure ce module, ajoutez les le code suivant au fichier build.gradle de votre application :

Groovy

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

Kotlin

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

Avec le module Fragment KTX, vous pouvez simplifier les transactions fragmentées avec la fonction lambdas. Exemple :

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

Vous pouvez également effectuer une liaison avec un ViewModel sur une ligne à l'aide des délégués de propriété viewModels et 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>()

Lifecycle KTX

Lifecycle KTX définit un LifecycleScope pour chaque objet Lifecycle. Toute coroutine lancée au sein de ce champ d'application est annulée lorsque Lifecycle est détruit. Vous pouvez accéder au CoroutineScope de Lifecycle à l'aide des propriétés lifecycle.coroutineScope ou lifecycleOwner.lifecycleScope.

Pour inclure ce module, ajoutez les le code suivant au fichier build.gradle de votre application :

Groovy

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

Kotlin

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

L'exemple suivant montre comment utiliser lifecycleOwner.lifecycleScope pour créer du texte précalculé de manière asynchrone :

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

Si vous utilisez LiveData, vous devrez peut-être calculer des valeurs de manière asynchrone. Par exemple, vous pouvez souhaiter récupérer les préférences d'un utilisateur et les transmettre à l'interface utilisateur. Pour ces cas, LiveData KTX fournit une fonction de constructeur liveData qui appelle une fonction suspend et transmet le résultat en tant qu'objet LiveData.

Pour inclure ce module, ajoutez les le code suivant au fichier build.gradle de votre application :

Groovy

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

Kotlin

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

Dans l'exemple suivant, loadUser() est une fonction de suspension déclarée ailleurs. Vous pouvez utiliser la fonction liveData du constructeur pour appeler loadUser() de manière asynchrone, puis utiliser emit() pour émettre le résultat :

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

Pour en savoir plus sur l'utilisation de coroutines avec LiveData, consultez la section Utiliser des coroutines Kotlin avec des composants d'architecture Android.

Chaque composant de la bibliothèque Navigation possède sa propre version KTX qui adapte l'API pour qu'elle soit plus concise et idiomatique Kotlin.

Pour inclure ces modules, ajoutez le code suivant au fichier build.gradle de votre application :

Groovy

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

Kotlin

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

Utilisez les fonctions d'extension et la délégation de propriété pour accéder aux arguments de destination et naviguer aux destinations, comme illustré dans l'exemple suivant :

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

Le module Palette KTX offre une prise en charge idiomatique de Kotlin pour l'utilisation des palettes de couleurs.

Pour utiliser ce module, ajoutez le code suivant au fichier build.gradle de votre application :

Groovy

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

Kotlin

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

Par exemple, lorsque vous utilisez une instance Palette, vous pouvez récupérer l'échantillon selected pour un target donné à l'aide de l'opérateur get ([ ]) :

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

Reactive Streams KTX

Le module Reactive Streams KTX vous permet de créer un flux LiveData observable à partir d'un éditeur ReactiveStreams.

Pour inclure ce module, ajoutez les le code suivant au fichier build.gradle de votre application :

Groovy

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

Kotlin

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

Prenons l'exemple d'une base de données avec une petite liste d'utilisateurs. Dans votre application, vous chargez la base de données en mémoire, puis vous affichez les données utilisateur dans l'interface utilisateur. Pour ce faire, vous pouvez utiliser RxJava. Le composant Room Jetpack peut récupérer la liste d'utilisateurs sous forme de Flowable. Dans ce scénario, vous devez également gérer l'abonnement de l'éditeur Rx tout au long du cycle de vie de votre fragment ou activité.

Avec LiveDataReactiveStreams, vous pouvez profiter de RxJava et de son riche ensemble d'opérateurs et de fonctionnalités de planification des tâches tout en bénéficiant de la simplicité de LiveData, comme illustré dans l'exemple suivant :

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

Room KTX

Les extensions Room ajoutent la prise en charge des coroutines pour les transactions de base de données.

Pour utiliser ce module, ajoutez le code suivant au fichier build.gradle de votre application :

Groovy

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

Kotlin

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

Voici quelques exemples où Room utilise désormais des coroutines. Le premier utilise une fonction suspend pour renvoyer une liste d'objets User, tandis que le second utilise Flow de Kotlin pour renvoyer de manière asynchrone la liste User. Notez que lorsque vous utilisez Flow, vous êtes également averti de toute modification dans les tables que vous interrogez.

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

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

SQLite KTX

Les extensions SQLite encapsulent le code lié aux requêtes SQL dans les transactions, éliminant ainsi une grande partie du code récurrent.

Pour utiliser ce module, ajoutez le code suivant au fichier build.gradle de votre application :

Groovy

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

Kotlin

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

Voici un exemple d'utilisation de l'extension transaction pour effectuer une transaction de base de données :

db.transaction {
    // insert data
}

ViewModel KTX

La bibliothèque ViewModel KTX fournit une fonction viewModelScope() qui permet de lancer plus facilement des coroutines à partir de votre ViewModel. Le CoroutineScope est lié à Dispatchers.Main et est automatiquement annulée lorsque le ViewModel est effacé. Vous pouvez utiliser viewModelScope() au lieu de créer un champ d'application pour chaque ViewModel.

Pour inclure ce module, ajoutez les le code suivant au fichier build.gradle de votre application :

Groovy

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

Kotlin

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

Par exemple, la fonction viewModelScope() suivante lance une coroutine qui effectue une requête réseau dans un thread d'arrière-plan. La bibliothèque gère l'ensemble de la configuration et la suppression du champ d'application correspondant :

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 offre une prise en charge de premier ordre pour les coroutines.

Pour inclure ce module, ajoutez les le code suivant au fichier build.gradle de votre application :

Groovy

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

Kotlin

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

Au lieu d'étendre Worker, vous pouvez maintenant étendre CoroutineWorker, qui possède une API légèrement différente. Par exemple, si vous souhaitez créer un CoroutineWorker simple pour effectuer certaines opérations réseau, vous pouvez procéder comme suit :

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

Pour plus d'informations sur l'utilisation de CoroutineWorker, consultez la rubrique Exécuter des threads dans CoroutineWorker.

WorkManager KTX ajoute également des fonctions d'extension à Operations et ListenableFutures pour suspendre la coroutine actuelle.

Voici un exemple qui suspend l'Operation renvoyé par enqueue() :

// Inside of a coroutine...

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

// Resume after work completes...

Autres modules KTX

Vous pouvez également inclure des modules KTX supplémentaires en dehors d'AndroidX.

Firebase KTX

Certains SDK Firebase pour Android disposent de bibliothèques d'extensions Kotlin qui vous permettent d'écrire du code Kotlin idiomatique lorsque vous utilisez Firebase dans votre application. Pour en savoir plus, consultez les pages suivantes :

Google Maps Platform KTX

Les extensions KTX disponibles pour les SDK Android de Google Maps Platform vous permettent de bénéficier de plusieurs fonctionnalités du langage Kotlin, telles que les fonctions d'extension, les paramètres nommés et les arguments par défaut, les déclarations de déstructuration et les coroutines. Pour plus d'informations, consultez les articles suivants :

Play Core KTX

Play Core KTX ajoute la prise en charge des coroutines Kotlin pour les requêtes de détection unique et Flow pour surveiller les mises à jour d'état en ajoutant des fonctions d'extension à SplitInstallManager et AppUpdateManager dans la bibliothèque Play Core.

Pour inclure ce module, ajoutez les le code suivant au fichier build.gradle de votre application :

Groovy

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

Kotlin

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

Voici un exemple de Flow de surveillance d'état :

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

Plus d'informations

Pour en savoir plus sur Android KTX, regardez la vidéo sur DevBytes.

Pour signaler un problème ou proposer une fonctionnalité, utilisez l'outil de suivi des problèmes Android KTX.