Kotlin Android¶
Introduzione¶
Kotlin è un linguaggio moderno perfetto per lo sviluppo di applicazioni Android che non introduce alcuna restrizione
Alcune caratteristiche dell’uso di Kotlin per lo sviluppo delle app Android:
Compatibilità: Kotlin è completamente compatibile con JDK 6, garantendo che le applicazioni Kotlin possano funzionare su dispositivi Android precedenti senza problemi. Gli strumenti di Kotlin sono pienamente supportati in Android Studio e compatibili con il sistema di build Android.
Prestazioni: un’applicazione Kotlin è veloce quanto una Java equivalente, grazie a una struttura bytecode molto simile. Con il supporto di Kotlin per le funzioni inline, il codice che utilizza lambda spesso viene eseguito anche più velocemente dello stesso codice scritto in Java.
Interoperabilità: Kotlin è al 100% interoperabile con Java, consentendo di utilizzare tutte le librerie Android esistenti in un’applicazione Kotlin. Ciò include l’elaborazione delle annotazioni, quindi anche il databinding e il Dagger funzionano.
Impatto: Kotlin ha una libreria runtime molto compatta, che può essere ulteriormente ridotta con l’uso di ProGuard. In un’applicazione reale, il runtime di Kotlin aggiunge solo poche centinaia di metodi e meno di 100K alla dimensione del file .apk.
Tempo di compilazione: Kotlin supporta ed è ottimizzato per la compilazione incrementale, quindi, per le build pulite c’è un sovraccarico, le build incrementali sono solitamente veloci o più veloci rispetto a Java.
Curva di apprendimento: per uno sviluppatore Java, iniziare a usare Kotlin è molto semplice. Il convertitore automatico da Java a Kotlin incluso nel plugin Kotlin aiuta con i primi passi. Kotlin Koans offre una guida attraverso le caratteristiche principali della lingua con una serie di esercizi interattivi.
Strumenti per lo sviluppo Android¶
Il team di Kotlin offre un set di strumenti per lo sviluppo Android che va oltre le funzionalità linguistiche standard:
Kotlin Android Extensions è un’estensione per compilatore che ti consente di sbarazzarti delle chiamate findViewById () nel tuo codice e di sostituirle con proprietà sintetiche generate dal compilatore.
Anko è una libreria che fornisce una serie di wrapper compatibili con Kotlin attorno alle API Android, oltre a una DSL che consente di sostituire i file .xml del layout con il codice Kotlin.
Sintassi di base¶
Definizione package¶
Il package va definito all’inizio del file:
package my.demo
import java.util.*
// ...
Definizione funzioni¶
Funzione con passaggio di due parametri di tipo Int che ritornerà un Int:
fun sum(a: Int, b: Int): Int {
return a + b
}
Funzione con nessun valore di ritorno (void di Java):
fun printSum(a: Int, b: Int): Unit {
println("sum of $a and $b is ${a + b}")
}
volendo :Unit si può omettere
Definizione variabili¶
Le variabili di sola lettura il cui valore può essere assegnato una sola volta vengono dichiarate con la chiave val:
val a: Int = 1 // assegnazione immediata
val b = 2 // assegnazione con tipologia deducibile in questo caso `Int`
val c: Int // Indicare la tipologia se la variabili non viene inizializzata
c = 3 // assegnazione di valore dopo la dichiarazione
Le variabili, invece, il cui valore può essere riassegnato vengono dichiarate con la chiave var:
var x = 5 // tipo `Int` deducibile
x += 1
Commenti¶
I commenti in Kotlin sono come quelli in Java, supportano sia il commento della singola riga che a blocco.
A differenza di Java, i commenti di blocco in Kotlin possono essere annidati.
// Commento riga singola
/* Commento in blocco
di più righe */
/*
Commento in blocco
/*
Commento in blocco annidato
*/
*/
Utilizzo delle stringhe¶
var a = 1
// aggiunta del nome `a` nel modello `s1`:
val s1 = "a is $a"
a = 2
// espressione complessa in un modello :
val s2 = "${s1.replace("is", "was")}, but now is $a"
Utilizzo delle espressioni condizionali¶
fun maxOf(a: Int, b: Int): Int {
if (a > b) {
return a
} else {
return b
}
}
//L'uso dell'if in una espressione
fun maxOf(a: Int, b: Int) = if (a > b) a else b
Utilizzo dei valori nulli e controllo per null¶
Bisogna esplicitamente indicare se un valore può ritornare null.
La funziona ritornerà null se non sarà un valore intero:
fun parseInt(str: String): Int? {
// ...
}
fun printProduct(arg1: String, arg2: String) {
val x = parseInt(arg1)
val y = parseInt(arg2)
// L'uso di `x * y` restituisce un errore perchè potrebbe contenere valori nulli.
if (x != null && y != null) {
// x e y vengono automaticamente convetiti in valore non nulli
println(x * y)
}
else {
println("'$arg1' o '$arg2' non sono numeri")
}
}
Utilizzo dei controlli sul tipo e i cast automatici¶
L’operatore is controlla se l’espressione è un’istanza di un tipo.
Se una variabile viene controllata per un tipo specifico, non è necessario eseguire il cast esplicito:
fun getStringLength(obj: Any): Int? {
if (obj is String) {
// `obj` viene automaticamente tipizzato `String` dopo questo controllo
return obj.length
}
// `obj` è ancora di tipo `Any` fuori dal controllo
return null
}
o
fun getStringLength(obj: Any): Int? {
if (obj !is String) return null
// `obj` è automaticamente tipizzato `String` dopo il controllo
return obj.length
}
o ancora
fun getStringLength(obj: Any): Int? {
// `obj` viene automaticamente tipizzato a `String` dopo `&&`
if (obj is String && obj.length > 0) {
return obj.length
}
return null
}
Utilizzo dei cicli¶
Ciclo for:
val items = listOf("apple", "banana", "kiwifruit")
for (item in items) {
println(item)
}
or
val items = listOf("apple", "banana", "kiwifruit")
for (index in items.indices) {
println("item at $index is ${items[index]}")
}
Ciclo while:
val items = listOf("apple", "banana", "kiwifruit")
var index = 0
while (index < items.size) {
println("item at $index is ${items[index]}")
index++
}
Utilizzo dell’espressioni when¶
Le espressioni when sono come degli swith ma più potenti:
fun describe(obj: Any): String =
when (obj) {
1 -> "One"
"Hello" -> "Greeting"
is Long -> "Long"
!is String -> "Not a string"
else -> "Unknown"
}
Utilizzo degli intervalli¶
Per controllare se un numero appartiene o meno a un intervallo si può utilizzare l’operatore in:
val x = 10
val y = 9
//controllo del valore x se contenuto nell'intervallo da 1 a y+1 (in questo caso 10)
if (x in 1..y+1) {
println("fits in range")
}
//ex. out of range
val list = listOf("a", "b", "c")
if (-1 !in 0..list.lastIndex) {
println("-1 is out of range")
}
if (list.size !in list.indices) {
println("list size is out of valid list indices range, too")
}
//ciclo su un intervallo
for (x in 1..5) {
print(x)
}
//circlo su un intervallo con pregressione
for (x in 1..10 step 2) {
print(x)
}
println()
for (x in 9 downTo 0 step 3) {
print(x)
}
Utilizzo delle collezioni¶
Cicli su delle collezioni
for (item in items) {
println(item)
}
//controlla se la collezione contiene gli oggetti
when {
"orange" in items -> println("juicy")
"apple" in items -> println("apple is fine too")
}
//utilizzo dell'espressione lambda per filtrare e mappare la collezione:
val fruits = listOf("banana", "avocado", "apple", "kiwifruit")
fruits
.filter { it.startsWith("a") }
.sortedBy { it }
.map { it.toUpperCase() }
.forEach { println(it) }
Creazioni di classi base e le loro istanze¶
val rectangle = Rectangle(5.0, 2.0) //non è necessaria la chiave 'new'
val triangle = Triangle(3.0, 4.0, 5.0)