Keddit – Parte 2: Sintaxe Kotlin, Segurança Nula e mais no Android

Tempo de leitura: 6 minutes

Parte 2: Sintaxe, Segurança Nula e mais …

Nesta parte, vamos nos concentrar em entender algumas sintaxes básicas da linguagem e também adicionar todo o código de que precisamos para MainActivity.kt a fim de abrir nosso fragmento.

 

Sintaxe Kotlin

Agora nossa MainActivity é um arquivo Kotlin e estamos prontos para começar a aprender a sintaxe. A primeira vez que você ver o código, pode causar um pouco de medo, mas acredite, você vai adorar! 😉

Kotlin é definido de várias maneiras e esta é uma delas (da qual gosto muito) que tenta incluir as características mais importantes em uma frase:

Kotlin é uma linguagem de programação concisa, segura e estaticamente tipada com foco na interoperabilidade com Java.

Vamos usar esta definição para começar a revisar nosso código gerado. Apresento aqui os dois arquivos MainActivity: arquivos Java e Kotlin.

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
    }
}

MainActivity.class: Antes de ser convertido

 

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val toolbar = findViewById(R.id.toolbar) as Toolbar
        setSupportActionBar(toolbar)

        val fab = findViewById(R.id.fab) as FloatingActionButton
        fab.setOnClickListener { view -> Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG).setAction("Action", null).show() }
    }
}

MainActivity.kt

 

Conciso

Você percebeu que o arquivo Java tem 19 linhas de código e o arquivo Kotlin tem apenas 12?

Isso ocorre porque a maior parte da verbosidade do Java foi eliminada. Um código conciso leva menos tempo para escrever e ler, portanto, isso aumentará sua produtividade.

 

Estender e implementar:

As palavras “extends” e “implement” foram substituídas por dois pontos “:” indiferentemente. Neste caso, estamos estendendo de AppCompatActivity (que é uma classe Java!)

class MainActivity : AppCompatActivity()

 

Fun — ctions

Não temos nossa estrutura clássica “public void methodName()”. Agora definimos funções dentro de nossa classe com a palavra-chave “fun” e o tipo de retorno é adicionado ao final. Mas onde é o tipo retornado de nosso método “onCreate”?

override fun onCreate(savedInstanceState: Bundle?) {

No caso de não querermos retornar nenhum valor em Java usaríamos “void”, aqui a alternativa é “Unit” que funciona da mesma forma. O compilador saberá que não estamos retornando nada, então podemos omiti-lo. No caso de querermos adicioná-lo, basta fazê-lo desta forma:

override fun onCreate(savedInstanceState: Bundle?) : Unit {

Além disso, os parâmetros estão em uma ordem diferente. Primeiro você define o nome da variável e depois o tipo.

Bye Semicolon;

Em Kotlin, você não precisa colocar o ponto-e-vírgula no final das frases, mas ainda pode fazer se quiser (não faça isso).

Valores e Variável

A forma de definir uma variável é com a palavra-chave “var”. O tipo será inferido do Contexto e o mesmo para constantes que usam a palavra-chave “val”:

val price = 100        // Int
price = 30             // não compile! é uma constante
var total = price * 3  // Int
val name = "Juancho"   // String

Você pode especificar o tipo explicitamente:

val lastname : String = "Keddit" // definição de tipo explícita
var size : Double = 30.0
var time : Float = 15f

Talvez você perceba que não existem tipos primitivos, não usamos “double”, mas “Double”. Isso ocorre porque tudo em Kotlin é um objeto. Para desempenho, o compilador transformará alguns desses objetos em tipos primitivos internamente.

 

Propriedades e campos

No Kotlin, você acessa propriedades como acessar um campo em Java. Em vez de chamar o método getResources() de uma Activity, você faz diretamente:

resources.getString(R.string.id)
// vs
getResources().getString(R.string.id) // ainda permitido

Você ainda pode chamar o método getResource(), mas o Android Studio irá sugerir que você o altere:

Não significa que você está acessando o campo diretamente, está chamando o método “getResource()”, mas de uma forma mais conveniente.

 

Esta é uma das grandes coisas sobre Kotlin, tudo em Kotlin não é anulável, a menos que você declare especificamente desta forma. A maneira de fazer isso é com o “?” ponto de interrogação que também sugere que o valor pode estar lá ou não.

Com isso dito, vamos ver alguns exemplos:

val a : String = null   // não compilar!
var b : Int             // nem como deve ser inicializado ou abstrato.
val ok : String? = null // OK :)

O compilador verificará a presença de um possível objeto nulo, o que nos impedirá de cometer o erro comum de obter uma “NullPointerException” ou conhecido como “erro de bilhões de dólares” de Tony Hoare.

Safe call

Para interagir com um objeto anulável é realmente fácil, o “?” ponto de interrogação permitirá que você obtenha o valor caso ele exista, caso contrário, ele irá ignorá-lo e você estará seguro para continuar executando o programa:

val context : Context? = null
val res = context?.getResources() // não travar, res será nulo

Smart cast

Se você continuar brincando com objetos anuláveis, talvez você acabe fazendo isso:

val context : Context? = null
val res = context?.getResources()
val appName = res?.getString(R.string.app_name)
val shortName = appName?.substring(0, 2)

Isso é horrível, mas você pode fazer isso de uma maneira melhor com um elenco inteligente. Basta verificar se o contexto é nulo e dentro do bloco if o contexto será considerado um objeto não anulável:

val context : Context? = null
if (context != null) {
    val res = context.getResources()    // Não precisa de '?' mais
    val appName = res.getString(R.string.app_name)
    val shortName = appName.substring(0, 2)
}
val context : Context? = null
context?.let {
    val res = context.getResources()    // Não precisa de '?' mais
    val appName = res.getString(R.string.app_name)
    val shortName = appName.substring(0, 2)
}
Elvis Operator ?

Elvis Operator ?:

Este é o nome usado para este operador “?:” E você pode usá-lo para fornecer um valor alternativo caso o objeto seja nulo. É como uma maneira curta de realizar uma verificação de nulos. Neste exemplo, “mensagem” pode ser nula, o tipo é “String?”. Caso o objeto NÃO seja nulo estaremos enviando o valor da mensagem, caso contrário, o valor que fornecemos após o operador elvis:

try {
    // code...
} catch (e: Throwable) {
    Log.e("TAG", e.message ?: "Error message")
}

Observação: se você quiser saber mais sobre segurança nula, verifique este link: https://kotlinlang.org/docs/reference/null-safety.html

Isso significa que Kotlin precisa saber o tipo de tudo que você define no código, porque o compilador fará uma verificação de tipo durante a compilação. Com o excelente suporte que temos no Android Studio (graças ao JetBrains), o IDE fará um ótimo trabalho nos ajudando a saber se estamos atribuindo corretamente um valor a uma variável.

Além disso, não temos que especificar o tipo quando criamos uma variável (ou uma constante neste caso). Verifique a constante da barra de ferramentas, o tipo é inferido do contexto e este é outro grande recurso do Kotlin:

val toolbar = findViewById(R.id.toolbar) as Toolbar

A inferência de tipo traz grandes vantagens para a linguagem: Confiabilidade (o compilador verifica a exatidão do programa), Manutenibilidade (o código é explicado por si mesmo), Suporte a ferramentas (o que mencionei antes, a tipagem estática permite refatoração confiável, preenchimento de código e muito mais) e Desempenho (na maioria dos casos, não há necessidade de descobrir em tempo de execução qual método precisa ser chamado).

100% de interoperabilidade Java

Este é outro ótimo recurso do Kotlin, você pode usar o código Java de um arquivo Kotlin e vice-versa. No aplicativo Keddit, estamos estendendo de AppCompatActivity, usando o objeto Bundle no método onCreate e, claro, usando todo o Android SDK para criar nosso aplicativo :). Além disso, estamos usando outras bibliotecas Java como Retrofit, Picasso, etc.

Algo muito importante sobre isso é que o Kotlin não tem sua própria biblioteca de coleções, ele depende de classes da biblioteca padrão Java, estendendo essas classes com novas funções. Isso significa que você nunca precisa converter objetos entre Java e Kotlin.

 

Atualizando MainActivity

Acabei de adicionar alguns métodos à MainActivity para abrir um fragmento que será criado na próxima história e também removi algum código que não precisamos, neste caso, todas as coisas relacionadas às configurações do menu.

Verifique o código para ver a atividade e tente entender esses novos conceitos:

https://github.com/caneto/KedditPorEtapas/blob/master/app/src/main/java/com/droidcba/kedditbysteps/MainActivity.kt

Observe como estou usando o Fragment Manager

val ft = supportFragmentManager.beginTransaction();
// e não getSupportFragmentManager()

O novo método “changeFragment()” nos permitirá abrir um fragmento dentro desta atividade com uma animação fade.

Repositório

https://github.com/caneto/KedditPorEtapas

 

Conclusão

Esta é apenas uma pequena parte de alguns conceitos do Kotlin, continuaremos aprendendo mais enquanto desenvolvemos o aplicativo Keddit.

Se quiser aprender mais sobre esses conceitos, dê uma olhada neste link que considero muito útil: http://try.kotlinlang.org/

Até a próxima história!

 

Artigo seguinte

Parte 3: NewsFragment.kt: Funções de extensão, extensões Android…