The Android Developer Challenge is back! Submit your idea before December 2.

Android KTX   Part of Android Jetpack.

Android KTX is a set of Kotlin extensions that are included with Android Jetpack and other Android libraries. KTX extensions provide concise, idiomatic Kotlin to Jetpack, Android platform, and other APIs. To do so, these extensions leverage several Kotlin language features, including the following:

  • Extension functions
  • Extension properties
  • Lambdas
  • Named parameters
  • Parameter default values
  • Coroutines

As an example, when working with SharedPreferences, you must create an editor before you can make modifications to the preferences data. You must also apply or commit those changes when you are finished editing, as shown in the following example:

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

Kotlin lambdas are a perfect fit for this use case. They allow you to take a more concise approach by passing a block of code to execute after the editor is created, letting the code execute, and then letting the SharedPreferences API apply the changes atomically.

Here's an example of one of the Android KTX Core functions, SharedPreferences.edit, which adds an edit function to SharedPreferences. This function takes an optional boolean flag as its first argument that indicates whether to commit or apply the changes. It also receives an action to perform on the SharedPreferences editor in the form of a 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) }

The caller can choose whether to commit or apply the changes. The action lambda is itself an anonymous extension function on SharedPreferences.Editor which returns Unit, as indicated by its signature. This is why inside the block, you are able to perform the work directly on the SharedPreferences.Editor.

Finally, the SharedPreferences.edit() signature contains the inline keyword. This keyword tells the Kotlin compiler that it should copy and paste (or inline) the compiled bytecode for the function each time the function is used. This avoids the overhead of instantiating a new class for every action each time this function is called.

This pattern of passing code using lambdas, applying sensible defaults that can be overridden, and adding these behaviors to existing APIs using inline extension functions is typical of the enhancements provided by the Android KTX library.

Use Android KTX in your project

To start using Android KTX, add the following dependency to your project's build.gradle file:

repositories {
    google()
}

Android KTX is organized into modules, where each module contains one or more packages.

You must include a dependency for each module artifact in your app's build.gradle file. Remember to append the version number to the artifact. For example, if you use the core-ktx module, the fully-formed dependency looks similar to the following:

dependencies {
    implementation 'androidx.core:core-ktx:1.0.1'
}

Modules

Android KTX contains a single core module that provides Kotlin extensions for common framework APIs and several domain-specific extensions.

With the exception of the core module, all KTX module artifacts replace the underlying Java dependency in your build.gradle file. For example, you can replace a androidx.fragment:fragment dependency with androidx.fragment:fragment-ktx. This syntax helps to better manage versioning and does not add additional dependency declaration requirements.

Core KTX

The Core KTX module provides extensions for common libraries that are part of the Android framework. These libraries do not have Java-based dependencies that you need to add to build.gradle.

Here's a list of the packages that are contained in the Core KTX module:

Fragment KTX

Dependency: androidx.fragment:fragment-ktx:$version. Be sure to define $version or replace it with a literal value.

The Fragment KTX module provides a number of extensions to simplify the fragment API. For example, you can simplify fragment transactions with lambdas:

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

You can also bind to a ViewModel in one line by using the viewModels and activityViewModels property delegates:

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

Palette KTX

Dependency: androidx.palette:palette-ktx:$version. Be sure to define $version or replace it with a literal value.

The Palette KTX module offers idiomatic Kotlin support for working with color palettes.

For example, when working with a Palette instance, you can retrieve the selected swatch for a given target by using the get operator ([ ]):

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

SQLite KTX

Dependency: androidx.sqlite:sqlite-ktx:$version. Be sure to define $version or replace it with a literal value.

SQLite extensions wrap SQL-related code in transactions, eliminating a lot of boilerplate code, as shown in the following example:

db.transaction {
    // insert data
}

Collection KTX

Dependency: androidx.collection:collection-ktx:$version. Be sure to define $version or replace it with a literal value.

The Collection extensions contain utility functions for working with Android's memory-efficient collection libraries, including ArrayMap, LongParseArray, LruCache, and others.

Collections extensions take advantage of Kotlin’s operator overloading to simplify things like collection concatenation, as shown in the following example:

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

ViewModel KTX

Dependency: androidx.lifecycle:lifecycle-viewmodel-ktx:$version. Define or replace $version to reflect the latest module version.

The ViewModel KTX library provides a viewModelScope() function that makes it easier to launch coroutines from your ViewModel. The CoroutineScope is bound to Dispatchers.Main and is automatically cancelled when the ViewModel is cleared. You can use viewModelScope() instead of creating a new scope for each ViewModel.

As an example, the following viewModelScope() function launches a coroutine that makes a network request in a background thread. The library handles all of the setup and corresponding scope clearing:

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

Reactive Streams KTX

Dependency: androidx.lifecycle:lifecycle-reactivestreams-ktx:$version. Be sure to define $version or replace it with a literal value.

Reactive Streams KTX module lets you create an observable LiveData stream from a ReactiveStreams publisher.

As an example, assume a database with a small list of users. In your app, you load the database into memory and then display user data in your UI. To achieve this, you might use RxJava. The Room Jetpack component can retrieve the user list as a Flowable. In this scenario, you must also manage the Rx publisher subscription across the life of your fragment or activity.

With LiveDataReactiveStreams, however, you can benefit from RxJava and its rich set of operators and work-scheduling capabilities while also working with the simplicity of LiveData, as shown in the following example:

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

Dependencies:

  • androidx.navigation:navigation-runtime-ktx:$version
  • androidx.navigation:navigation-fragment-ktx:$version
  • androidx.navigation:navigation-ui-ktx:$version

Be sure to define $version or replace it with a literal value.

Each component of the Navigation library has its own KTX version that adapts the API to be more succinct and Kotlin-idiomatic.

Use the extension functions and property delegation to access destination arguments and navigate to destinations, as shown in the following example:

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

}

WorkManager KTX

Dependency: androidx.work:work-runtime-ktx:$version. Be sure to define $version or replace it with a literal value.

WorkManager KTX adds support for Kotlin coroutines by adding extension functions to Operations and ListenableFutures to suspend the current coroutine, as shown in the following example:

// Inside of a coroutine...

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

// Resume after work completes...

Play Core KTX

Dependency: com.google.android.play:core-ktx:$version. Be sure to define $version or replace it with a literal value.

Play Core KTX adds support for Kotlin coroutines for one-shot requests and Flow for monitoring status updates by adding extension functions to SplitInstallManager and AppUpdateManager in the Play Core library.

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

More information

To learn more about Android KTX, see the DevBytes video.

To report an issue or suggest a feature, use the Android KTX issue tracker.