O Google tem o compromisso de promover a igualdade racial para as comunidades negras. Saiba como.

Android KTX   Parte do Android Jetpack.

O Android KTX é um conjunto de extensões Kotlin que fazem parte do Android Jetpack e de outras bibliotecas do Android. Com as extensões do KTX, o Jetpack, a Plataforma Android e outras APIs podem fazer uso de uma linguagem Kotlin concisa e idiomática. Para isso, essas extensões usam vários recursos do Kotlin, incluindo:

  • Funções da extensão
  • Propriedades de extensão
  • Lambdas
  • Parâmetros nomeados
  • Valores padrão de parâmetro
  • Corrotinas

Por exemplo, ao trabalhar com SharedPreferences, é preciso criar um editor para poder fazer modificações nos dados de preferências. Você também precisa aplicar ou confirmar essas modificações ao terminar de editar, conforme mostrado no exemplo a seguir:

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

Usar lambdas do Kotlin é ideal neste caso de uso. Com elas, você pode adotar uma abordagem mais concisa passando um bloco de código para execução após a criação do editor, permitindo que o código seja executado e que a API SharedPreferences aplique as mudanças atomicamente.

Veja um exemplo de uma das funções principais do Android KTX, SharedPreferences.edit, que adiciona uma função de edição a SharedPreferences. Essa função usa uma sinalização boolean opcional como o primeiro argumento, que indica se as mudanças serão confirmadas ou aplicadas. Ela também recebe uma ação para executar no editor SharedPreferences na forma de 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) }

O autor da chamada pode escolher entre confirmar ou aplicar as mudanças. A lambda action é, por si só, uma função de extensão anônima em SharedPreferences.Editor que retorna Unit, conforme indicado pela assinatura. É por isso que, dentro do bloco, você pode executar o trabalho diretamente no SharedPreferences.Editor.

Por fim, a assinatura SharedPreferences.edit() traz a palavra-chave inline. Essa palavra-chave informa ao compilador do Kotlin que ele precisa copiar e colar (ou tornar inline) o bytecode compilado para a função sempre que ela for usada. Isso evita a sobrecarga de instanciar uma nova classe para cada action sempre que essa função for chamada.

Esse padrão de passagem de código usando lambdas, aplicação de padrões sensíveis que podem ser substituídos e adição desses comportamentos a APIs existentes usando funções de extensão inline é comum entre as melhorias trazidas pela biblioteca Android KTX.

Usar o Android KTX no projeto

Para começar a usar o Android KTX, adicione a seguinte dependência ao arquivo build.gradle do projeto:

repositories {
    google()
}

Módulos do AndroidX

O Android KTX é organizado em módulos, e cada módulo contém um ou mais pacotes.

É necessário incluir uma dependência para cada artefato do módulo no arquivo build.gradle do app. Lembre-se de anexar o número da versão ao artefato. Encontre os números de versão mais recentes em cada seção correspondente do artefato neste tópico.

O Android KTX contém um único módulo principal que fornece extensões Kotlin para APIs de framework comuns e várias extensões específicas do domínio.

Com exceção do módulo principal, todos os artefatos de módulo do KTX substituem a dependência Java subjacente no arquivo build.gradle. Por exemplo, você pode substituir uma dependência androidx.fragment:fragment por androidx.fragment:fragment-ktx. Essa sintaxe ajuda a gerenciar melhor o controle de versões e não gera outros requisitos de declaração de dependência.

Core KTX

O módulo Core KTX oferece extensões para bibliotecas comuns que fazem parte do framework do Android. Essas bibliotecas não têm dependências baseadas em Java que você precisa adicionar a build.gradle.

Para incluir este módulo, adicione o seguinte código ao arquivo build.gradle do seu app:

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

Veja a seguir uma lista dos pacotes contidos no módulo Core KTX:

Collection KTX

As extensões Collection trazem funções utilitárias para trabalhar com bibliotecas de coleções que fazem uso eficiente da memória do Android, incluindo ArrayMap, LongSparseArray, LruCache e outras.

Para usar este módulo, adicione o seguinte código ao arquivo build.gradle do seu app:

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

As extensões Collection aproveitam a sobrecarga de operadores do Kotlin para simplificar alguns processos, como a concatenação de coleções, conforme a seguir:

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

O módulo Fragment KTX fornece diversas extensões para simplificar a API do fragmento.

Para incluir este módulo, adicione o seguinte código ao arquivo build.gradle do seu app:

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

Com o módulo Fragment KTX, é possível simplificar transações fragmentadas com lambdas, por exemplo:

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

Você também pode vincular um ViewModel a uma linha usando as delegações de propriedade viewModels e 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

O Lifecycle KTX define um LifecycleScope para cada objeto Lifecycle. Qualquer corrotina iniciada nesse escopo será cancelada quando o Lifecycle for destruído. Acesse CoroutineScope de Lifecycle usando as propriedades lifecycle.coroutineScope ou lifecycleOwner.lifecycleScope.

Para incluir este módulo, adicione o seguinte código ao arquivo build.gradle do seu app:

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

O exemplo a seguir demonstra como usar lifecycleOwner.lifecycleScope para criar um texto pré-computado de forma assíncrona:

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

Ao usar LiveData, talvez seja necessário calcular valores de forma assíncrona. Por exemplo, caso você queira recuperar as preferências de um usuário e exibi-las na IU. Para esses casos, o LiveData KTX fornece uma função do builder liveData que chama uma função suspend e veicula o resultado como um objeto LiveData.

Para incluir este módulo, adicione o seguinte código ao arquivo build.gradle do seu app:

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

No exemplo a seguir, loadUser() é uma função de suspensão declarada em outro lugar. É possível usar a função do builder liveData para chamar loadUser() de maneira assíncrona e, em seguida, usar emit() para emitir o resultado:

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

Para ver mais informações sobre o uso de corrotinas com LiveData, consulte Usar corrotinas do Kotlin com componentes de arquitetura.

Cada componente da biblioteca Navigation tem a própria versão KTX que adapta a API para ser mais sucinta e idiomática para o Kotlin.

Para incluir esses módulos, adicione o seguinte código ao arquivo build.gradle do seu app:

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

Use as funções de extensão e a delegação de propriedade para acessar os argumentos de destinos e navegar para eles, conforme mostrado no exemplo a seguir:

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

O módulo Palette KTX é compatível com Kotlin idiomático para trabalhar com paletas de cores.

Para usar este módulo, adicione o seguinte código ao arquivo build.gradle do seu app:

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

Por exemplo, ao trabalhar com uma instância Palette, você pode recuperar a amostra selected para um determinado target usando o operador get ([ ]):

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

Reactive Streams KTX

O módulo Reactive Streams KTX permite criar um stream LiveData observável em um editor ReactiveStreams.

Para incluir este módulo, adicione o seguinte código ao arquivo build.gradle do seu app:

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

Como exemplo, considere um banco de dados com uma pequena lista de usuários. No app, você carrega o banco de dados na memória e, depois, exibe os dados do usuário na IU. Para fazer isso, é possível usar RxJava. O componente Room do Jetpack pode recuperar a lista de usuários como um Flowable. Nesse cenário, você também precisa gerenciar a assinatura do editor de Rx durante a vida útil do fragmento ou atividade.

Com LiveDataReactiveStreams, no entanto, você pode se beneficiar do RxJava e do amplo conjunto de operadores e recursos de agendamento de tarefa, além de trabalhar com a simplicidade de LiveData, como mostrado no exemplo a seguir:

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

Room KTX

As extensões Room são compatíveis com corrotinas para transações de banco de dados.

Para usar este módulo, adicione o seguinte código ao arquivo build.gradle do seu app:

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

Veja alguns exemplos de corrotinas usadas com o Room. O primeiro exemplo usa uma função suspend para retornar uma lista de objetos User, enquanto o segundo usa Flow do Kotlin para retornar de maneira assíncrona a lista User. Observe que, ao usar Flow, você também será notificado sobre quaisquer mudanças nas tabelas que estiver consultando.

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

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

SQLite KTX

As extensões SQLite unem o código relacionado a SQL em transações, eliminando uma grande quantidade de código boilerplate.

Para usar este módulo, adicione o seguinte código ao arquivo build.gradle do seu app:

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

Veja um exemplo de como usar a extensão transaction para executar uma transação de banco de dados:

db.transaction {
    // insert data
}

ViewModel KTX

A biblioteca ViewModel KTX fornece uma função viewModelScope() que facilita iniciar corrotinas no ViewModel. O CoroutineScope está vinculado ao Dispatchers.Main e será automaticamente cancelado quando o ViewModel for liberado. Você pode usar viewModelScope() em vez de criar um novo escopo para cada ViewModel.

Para incluir este módulo, adicione o seguinte código ao arquivo build.gradle do seu app:

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

Como exemplo, a seguinte função viewModelScope() inicia uma corrotina que faz uma solicitação de rede em uma linha de execução em segundo plano. A biblioteca processa toda a configuração e a limpeza do escopo correspondente:

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

O WorkManager KTX tem alta compatibilidade com corrotinas.

Para incluir este módulo, adicione o seguinte código ao arquivo build.gradle do seu app:

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

Agora, em vez de estender Worker, você pode estender CoroutineWorker, que tem uma API um pouco diferente. Por exemplo, se você quiser criar um CoroutineWorker simples para executar algumas operações de rede, faça o seguinte:

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

Para ver mais informações sobre o uso de CoroutineWorker, consulte Linhas de execução no CoroutineWorker.

O WorkManager KTX também adiciona funções de extensão a Operations e ListenableFutures para suspender a corrotina atual.

Veja um exemplo que suspende o Operation retornado por enqueue():

// Inside of a coroutine...

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

// Resume after work completes...

Outros módulos KTX

Você também pode incluir módulos KTX adicionais que existam fora do AndroidX.

Firebase KTX

Alguns dos SDKs do Firebase para Android têm bibliotecas de extensão Kotlin que permitem escrever códigos idiomáticos do Kotlin ao usar o Firebase no seu aplicativo. Para ver mais informações, consulte os seguintes tópicos:

KTX para a Plataforma Google Maps

Há extensões KTX disponíveis para os SDKs do Android da Plataforma Google Maps que permitem aproveitar vários recursos da linguagem Kotlin, como funções de extensão, argumentos padrão e parâmetros nomeados, declarações de desestruturação e corrotinas. Para ver mais informações, consulte os seguintes tópicos:

Play Core KTX

O Play Core KTX é compatível com corrotinas Kotlin para solicitações únicas e fluxo para monitoramento de atualizações de status adicionando funções de extensão a SplitInstallManager e AppUpdateManager na biblioteca Play Core.

Para incluir este módulo, adicione o seguinte código ao arquivo build.gradle do seu app:

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

Veja um exemplo de monitoramento de status 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()
    }
}

Mais informações

Para saber mais sobre o Android KTX, veja o vídeo DevBytes (em inglês).

Para informar um problema ou sugerir um recurso, use o Issue Tracker do Android KTX.