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 incluído no Android Jetpack e em outras bibliotecas do Android. As extensões do KTX oferecem Kotlin conciso e idiomático para o Jetpack, a Plataforma Android e outras APIs. Para isso, essas extensões utilizam vários recursos da linguagem 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, você precisa criar um editor para poder fazer modificações nos dados de preferências. Você também precisa aplicar ou confirmar essas modificações quando terminar de editar, conforme mostrado no exemplo a seguir:

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

As lambdas do Kotlin são perfeitas para este 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 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 uma 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() contém a palavra-chave inline. Essa palavra-chave informa ao compilador Kotlin de que ele precisa copiar e colar (ou 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 é típico das melhorias fornecidas 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 central 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 central, 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ão 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ê precise adicionar a build.gradle.

Para incluir este módulo, adicione o seguinte 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 de coleção contêm funções de utilitário para trabalhar com bibliotecas de coleções com uso eficiente da memória do Android, incluindo ArrayMap, LongParseArray, LruCache e outras.

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

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

As extensões de coleção aproveitam a sobrecarga de operadores do Kotlin para simplificar algumas coisas, como a concatenação de coleções, como mostrado no exemplo 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 de fragmento.

Para incluir este módulo, adicione o seguinte 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 em 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 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 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 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 criador liveData que chama um suspend e veicula o resultado como um objeto LiveData.

Para incluir este módulo, adicione o seguinte 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 criador 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 mais informações sobre o uso de corrotinas com LiveData, consulte Usar corrotinas 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 ao arquivo build.gradle do seu app:

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

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 oferece compatibilidade com Kotlin idiomático para trabalhar com paletas de cores.

Para usar este módulo, adicione o seguinte 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 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, em seguida, exibe os dados do usuário na IU. Para conseguir 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 ao longo da vida útil do seu 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

Extensões do Room oferecem compatibilidade a corrotinas para transações de banco de dados.

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

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

Veja alguns exemplos em que Room usa corrotinas. O primeiro exemplo usa uma função suspend para retornar uma lista de objetos User, enquanto o segundo usa Flow de 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 de texto clichê.

Para usar este módulo, adicione o seguinte 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 (link em inglês). Você pode usar viewModelScope() em vez de criar um novo escopo para cada ViewModel.

Para incluir este módulo, adicione o seguinte 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 oferece compatibilidade de primeira classe para corrotinas.

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

dependencies {
    implementation "androidx.work:work-runtime-ktx:2.4.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 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 mais informações, consulte os seguintes tópicos:

KTX da 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 mais informações, consulte os tópicos a seguir:

Play Core KTX

O Play Core KTX adiciona compatibilidade 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 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 rastreador de problemas do Android KTX (link em inglês).