Programação Avançada Kotlin

Tempo de leitura: 6 minutes

Se você é novo no Kotlin, verifique meu post anterior no Guia de Kotlin para Iniciantes antes de prosseguir para um melhor entendimento. Nesta postagem, vamos verificar algumas coisas básicas e interessantes sobre as funções no Kotlin.

 

Como escrever funções ou métodos em Kotlin?

Uma função nada mais é que uma coleção de instruções. Uma função precisa ser chamada explicitamente para executar esse bloco de instruções. Para manter a legibilidade e a facilidade de compreensão, escrevemos n número de funções em nossas classes. Métodos são usados ​​para executar certas ações.

Uma função deve ser declarada dentro de uma classe. Para declarar um método em Kotlin, precisamos principalmente de três parâmetros diferentes

  • fun – No Kotlin, as funções são declaradas com a palavra-chave fun
  • name – Precisamos ter um nome exclusivo para cada método
  • () – parênteses que é comum para declarações de método na maioria das linguagens de programação
fun doSomeThing() {
        print("Bem-vindo ao Kotlin")
    }

A função acima é uma função simples que imprime “Bem-vindo ao Kotlin” quando executada.

Exemplo Explicado

  • doSomeThing() é o nome do método
  • {} – é o bloco do método que define o início e o fim do método

Além disso, precisamos saber mais algumas coisas relacionadas aos métodos.

 

Parâmetros ou Argumentos

Se quisermos passar alguma informação aos métodos, podemos enviá-la como parâmetro. Eles atuam como variáveis ​​locais dentro do bloco de método. Os parâmetros são especificados entre parênteses () do método. Podemos adicionar quantos parâmetros quisermos, apenas separando-os com uma vírgula.

O exemplo de uma função parametrizada é o seguinte

Funcao de exemplo

 

Tipo de Retorno

Um tipo de retorno especifica se um método ou função deseja retornar algo ou não. Na linguagem Kotlin, se um método deseja retornar algo, precisamos especificar o tipo de retorno da função e o valor de retorno do método junto com a palavra-chave return (opcional). Dê uma olhada no seguinte trecho

Exemplo

Aqui está um caso de uso simples de adicionar dois números e retornar o resultado. Mas no cenário de caso real, imagine onde temos uma URL e queremos fazer o download do arquivo de imagem, então aqui escrevemos um método passando URL como um argumento para esse método, como dowloadImage (url: String) e dentro do método, escrevemos todos os coisas de baixar a imagem e, finalmente, retornar o arquivo de imagem.

Como Kotlin é uma linguagem amigável, podemos escrever o mesmo método de adição de maneiras diferentes, mas o resultado é o mesmo

fun add(a: Int, b: Int): Int {
    return a + b
}

fun add(a: Int, b: Int) = a + b

fun add(a: Int, b: Int): Int = a + b

Isso é tudo sobre os fundamentos da função de escrita em Kotlin. Agora vamos aprender alguns conceitos avançados com suporte no Kotlin.

 

Conceitos avançados relacionados a funções em Kotlin

Argumentos Padrão

No Kotlin, temos uma opção de argumentos padrão nas declarações de função. Isso significa que os argumentos da função podem ter valores padrão, que foram usados ​​quando um argumento correspondente foi omitido da chamada da função. Não era compatível com Java. Isso permite um número reduzido de sobrecargas em comparação com outras linguagens de programação.

fun foo(i: Int = 10){
    print(i)
}

portanto, se chamarmos foo() em qualquer lugar, ele será executado e imprimirá o valor padrão e se fornecermos quaisquer valores, o valor padrão será substituído pelo valor fornecido durante a chamada do método.

 

Argumentos nomeados

Os parâmetros da função podem ser nomeados ao chamar as funções. É uma maneira muito conveniente quando uma função tem um número maior de parâmetros ou argumentos padrão variáveis. Enquanto o método chama, podemos usar esse nome para fornecer o valor. Vamos dar uma olhada em uma função

fun printMyDetails(str: String,
             isValid: Boolean = true,
             isUpperCase: Boolean = true,
             firstLetter: Char = ' ') {
......
}

Podemos chamar isso usando o argumento padrão:

printMyDetails(str)

senão podemos passar todos os argumentos para sobrescrever os valores padrão

printMyDetails(str, true, true, false, 's')

mas aqui na chamada de método acima, podemos nos confundir com qual valor booleano especificado para quais argumentos. Então, aqui está como podemos usar argumentos nomeados

printMyDetails(str,
    isValid = true,
    isUpperCase = true,
    firstLetter = 'a'
)

É assim que ficaria muito claro e facilmente compreensível.

 

Extensões Kotlin

As extensões são um dos conceitos amplamente usados ​​da seleção de Kotlin.

De acordo com a documentação de Kotlin:

“Kotlin oferece a capacidade de estender uma classe com novas funcionalidades sem ter que herdar da classe ou usar padrões de design como Decorator. Isso é feito por meio de declarações especiais chamadas extensões. ”

Isso significa que, sem herdar uma classe, podemos estender ou personalizar sua funcionalidade. Quando estamos usando uma biblioteca de terceiros, podemos simplesmente escrever novas funções para uma classe sem modificar a classe real. Esse mecanismo é chamado de funções de extensão.

Na verdade, esse era um recurso muito interessante, então agora se tornou comum, já que a maioria das pessoas o está usando em todos os lugares para customização e para reduzir o código clichê.

Vejamos um exemplo básico de como mostrar uma mensagem de brinde dentro de uma atividade.

Para mostrar uma mensagem brinde, geralmente escrevemos uma frase comum como

Toast.makeText(this, "message", Toast.LENGTH_SHORT).show()

E, geralmente, é uma prática comum de mostrar mensagens do brinde em várias atividades e repetir a mesma linha em vários pontos e importações desnecessárias da classe do brinde em todos os lugares.

Portanto, para reduzir isso, podemos criar uma função de extensão do sistema toast e chamá-la em qualquer lugar. Podemos criar uma função de extensão em Activity ou Fragment ou simplesmente em Context. Vamos verificar o contexto

fun Context.toast(msg: String, duration: Int = Toast.LENGTH_SHORT) {
    Toast.makeText(this, msg, duration).show()
}

E podemos chamar isso de qualquer atividade, passando uma mensagem para mostrar como

toast(getString(R.string.something_wentwrong))

A seguir está a lista de funções de extensão baseadas em contexto que uso em meus projetos para remover código clichê e aumentar a produtividade

package com.example.utils.extensions

import android.content.Context
import android.util.TypedValue
import android.widget.Toast
import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import androidx.annotation.DimenRes
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat


@ColorInt
fun Context.getColorCompat(@ColorRes resourceId: Int) = ContextCompat.getColor(this, resourceId)

fun Context.getDrawableCompat(@DrawableRes resId: Int) = ContextCompat.getDrawable(this, resId)

fun Context.getDimension(@DimenRes resourceId: Int) = resources.getDimension(resourceId)

val Context.screenWidth: Int
    get() = resources.displayMetrics.widthPixels

val Context.screenHeight: Int
    get() = resources.displayMetrics.heightPixels

fun Context.toast(msg: String, duration: Int = Toast.LENGTH_SHORT) {
    Toast.makeText(this, msg, duration).show()
}

fun Co
ntext.getPxFromDp(dp: Float) = TypedValue
    .applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, resources.displayMetrics).toInt()

As extensões são resolvidas estaticamente, o que significa que a função de extensão que está sendo chamada é determinada pelo tipo de expressão na qual a função é invocada, não pelo tipo de resultado da avaliação dessa expressão em tempo de execução” – dos documentos Kotlin

 

Extensão padrão fornecida por Kotlin

Existem também algumas extensões Kotlin predefinidas ou padrão que podemos usar. Vamos verificar algumas extensões padrão em coleções como filter, firstOrNull

filter – Retorna uma lista contendo apenas os elementos que correspondem à condição ou predicado fornecido.

public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
    return filterTo(ArrayList<T>(), predicate)
}

 

Não é bom? Em Java, usamos para escrever todos os loops, iterar e fazer as coisas.

FirstOrNull – retorna o primeiro elemento, ou um `nulo` se a coleção estiver vazia.

public fun <T> Iterable<T>.firstOrNull(): T? {
    when (this) {
        is List -> {
            if (isEmpty())
                return null
            else
                return this[0]
        }
        else -> {
            val iterator = iterator()
            if (!iterator.hasNext())
                return null
            return iterator.next()
        }
    }
}

Você saberá mais sobre eles e como eles são úteis ao usá-los. Então experimente.

 

Funções de alta ordem

Uma função que pode assumir uma função como parâmetro ou tem um tipo de função de retorno é chamada de funções de ordem superior. Qualquer uma das condições deve ser atendida

  • aceita uma função como parâmetro
  • retorna uma função

Dê uma olhada no trecho simples

fun multiply(a: Int, b: Int): Int {
    return a * b
}

fun returnMultiplyFunction(): ((Int, Int) -> Int) {
    return ::multiply
}

O uso mais comum é o tratamento do clique do adaptador Recyclerview. Com o clique de um item em um adaptador, precisamos passar alguns dados de volta para que possamos lidar com isso de forma eficiente.

Dentro da atividade ou fragmento ao definir o adaptador, precisamos passar um método onde, com o clique de um item dentro do adaptador, apenas invocamos o bloco dentro do adaptador para que o código no respectivo fragmento ou atividade seja executado.

A seguir está o snippet para passar a função da atividade para o adaptador

private val sideNavAdapter: SideNavAdapter = SideNavAdapter {position, item ->
        onItemClick(position,item)
    }

    private fun onItemClick(position: Int, item: SideNavItem) {
     //Custom Handling of item depending on our requirements 
      .....
    }

A seguir está o snippet de invocação da função passada com os argumentos necessários dentro do adaptador

class SideNavAdapter(private val onItemClick: ((position: Int, item: SideNavItem) -> Unit)) :
    RecyclerView.Adapter<SideNavAdapter.SideNavVH>() {
 
    var menuItemsList = ArrayList<SideNavItem>()

    inner class SideNavVH(inflate: View) : RecyclerView.ViewHolder(inflate) {
        var sideNavItem : SideNavItem?=null
        init {
            itemView.setOnClickListener {
                sideNavItem.let {
                    onItemClick.invoke(adapterPosition, sideNavItem)
                }
            }
        }
        fun setData(sideNavItem: SideNavItem) {
            this.sideNavItem = sideNavItem
            itemView.iv_nav?.setImageResource(sideNavItem.resourceId)
            itemView.tv_nav_name?.text = sideNavItem.itemName
        }
    }
    ......
}

 

Resumo

Pensei em compartilhar meu conhecimento para que pudesse ajudar alguém lá fora, então comecei a escrever uma série de postagens sobre os recursos do Kotlin.