Kotlin è il linguaggio principale per lo sviluppo Android. Secondo Google Android Docs (2025), oltre il 95% dei nuovi progetti Android utilizza Kotlin. Comprendere le specificità di Kotlin — data class, sealed class, coroutine e scope functions — è un requisito obbligatorio per uno sviluppatore Android.
Punti Chiave
Kotlin estende i concetti di classe di Java. data class, sealed class, object e companion object — costrutti che non esistono in Java o sono implementati diversamente.
data class — una classe che genera automaticamente equals(), hashCode(), toString(), copy() e componentN(). Ideale per modelli dati (DTO, Entity). Requisiti: almeno un parametro nel costruttore primario, val/var, non può essere open/sealed/inner. sealed class — una classe con una gerarchia di sottoclassi ristretta. Tutte le sottoclassi sono note in fase di compilazione e dichiarate nello stesso file. L'espressione when con sealed class non richiede un ramo else. sealed interface (Kotlin 1.9+) — come sealed class ma permette l'ereditarietà multipla. object — un singleton, dichiarato con la parola chiave object (non class). Inizializzazione lazy thread-safe. companion object — membri statici di una classe. Ha un nome (Companion di default). Può implementare interfacce e avere extension functions.
| Tipo | Descrizione | Utilizzo |
|---|---|---|
| data class | Generazione automatica di equals, hashCode, toString, copy | Modelli dati, DTO, Entity |
| sealed class | Gerarchia ristretta, controllo when | Stati, Risultato, UI State |
| sealed interface | sealed class + ereditarietà multipla | Eventi, Azioni (Kotlin 1.9+) |
| object | Singleton (dichiarativo) | Factory, Utility, Costanti |
| companion object | Membri statici della classe | Factory Method, costanti statiche |
| enum class | Enumerazione con costanti | Stati con insieme fisso |
data class — per il 90% dei modelli. sealed class — per UI State e Risultato. object — per singleton. IT Sectr raccomanda sealed class per tutti gli stati dello schermo (Loading, Success, Error).
Sealed class — un potente strumento per modellare gli stati. Esempio: UiState<T> con sottoclassi Loading, Success(data: T), Error(message: String). L'espressione when garantisce la gestione di tutti gli stati. Sealed interface — per eventi e azioni dove è necessaria implementazione multipla. Value class (Kotlin 1.5+) — un wrapper per un singolo valore senza overhead. Usato per identificatori type-safe: @JvmInline value class UserId(val id: String).
Extension Function — aggiungere un metodo a una classe esistente senza ereditarietà. fun String.isEmail(): Boolean. Extension Property — lo stesso per le proprietà (senza backing field). Inline Function — inserimento del corpo della funzione nel punto di chiamata — senza overhead di chiamata. Usato per higher-order functions con lambda. Higher-Order Function — una funzione che accetta o restituisce un'altra funzione. Scope Functions — cinque funzioni per lavorare con il contesto dell'oggetto: let, run, with, apply, also.
let — contesto it, restituisce il risultato della lambda. Usato per chiamate null-safe (?.let {}). apply — contesto this, restituisce il contesto. Per configurazione dell'oggetto. run — contesto this, restituisce il risultato della lambda. Per calcoli con contesto. also — contesto it, restituisce il contesto. Per effetti collaterali (logging). with — non è extension, contesto this, restituisce il risultato della lambda. Per un gruppo di operazioni su un oggetto. Lambda — funzione anonima. Destructuring Declaration — decompressione di data class in variabili: val (name, age) = person.
Inline function con reified — l'unico modo per preservare un tipo generico nella JVM. Usato per: builder type-safe (Gson.fromJson<T>()), controllo dei tipi (is T), ottenimento della classe (T::class). Crossinline e Noinline — modificatori per parametri lambda nelle funzioni inline. crossinline — vieta il non-local return, noinline — vieta l'inlining di una lambda specifica. IT Sectr raccomanda inline + reified solo quando si lavora con i tipi; per le normali higher-order functions, inline può aumentare la dimensione del bytecode.
Coroutine — thread leggeri per la programmazione asincrona. Non bloccano il thread — si sospendono. suspend function — una funzione che può essere sospesa senza bloccare il thread. Può essere chiamata solo da una coroutine o da un'altra suspend function.
CoroutineScope — un ambito per le coroutine. Contiene CoroutineContext (Job + Dispatcher). lifecycleScope — per Activity/Fragment (Lifecycle-aware). viewModelScope — per ViewModel (cancellazione automatica a onCleared()). GlobalScope — ambito globale (non raccomandato in produzione — perdite di memoria). Dispatchers: Dispatchers.Main (UI), Dispatchers.IO (rete/disco), Dispatchers.Default (CPU-intensive), Dispatchers.Unconfined (non raccomandato). launch — avvia una coroutine: Job. async — avvia con risultato: Deferred<T>. runBlocking — ponte bloccante. withContext — cambia Dispatcher all'interno di una suspend function.
// Esempio di coroutine: caricamento dati in ViewModel
class MainViewModel : ViewModel() {
private val _state = MutableStateFlow<UiState>(UiState.Loading)
val state: StateFlow<UiState> = _state.asStateFlow()
fun loadData() {
viewModelScope.launch {
_state.value = UiState.Loading
try {
val data = withContext(Dispatchers.IO) {
repository.fetchData()
}
_state.value = UiState.Success(data)
} catch (e: Exception) {
_state.value = UiState.Error(e.message)
}
}
}
}
// Richieste parallele con async
suspend fun loadCombinedData(): CombinedData = coroutineScope {
val users = async(Dispatchers.IO) { api.getUsers() }
val posts = async(Dispatchers.IO) { api.getPosts() }
CombinedData(users.await(), posts.await())
}viewModelScope.launch — avvio standard di coroutine in ViewModel. withContext(Dispatchers.IO) — passaggio al thread IO per richiesta di rete. Dispatchers determinano su quale pool di thread viene eseguita la coroutine. IT Sectr raccomanda viewModelScope per ViewModel e lifecycleScope per Activity/Fragment.
reified — un modificatore di tipo nelle funzioni inline. Permette di usare il tipo: T::class, is T, as T. Senza reified, i generics nella JVM vengono cancellati (type erasure). inline fun + reified — una combinazione potente per API type-safe. Destructuring Declaration — val (x, y) = point. Funziona per data class e tipi con componentN(). typealias — alias di tipo: typealias Callback = (String) -> Unit. lateinit — inizializzazione differita di var (per dependency injection). Non thread-safe. lazy — inizializzazione lazy di val (thread-safe di default). lazy(LazyThreadSafetyMode.NONE) — senza sincronizzazione. Extension function e Extension property — aggiungere funzionalità senza ereditarietà. Kotlin è un linguaggio in cui le extension functions risolvono il 90% dei compiti di utilità.
Delegated Properties — delegare getter/setter a un altro oggetto. Delegati standard: lazy, observable, vetoable, map. Delegato personalizzato tramite operatori getValue/setValue. by — parola chiave di delega: val name by lazy { loadName() }. Le proprietà delegate sono la base per i delegati ViewModel (by viewModels()). IT Sectr raccomanda lazy per l'inizializzazione differita e Delegates.observable per osservare i cambiamenti.
| Funzionalità | Descrizione | Esempio |
|---|---|---|
| reified | Preservazione del tipo generico in inline | inline fun <reified T> parse(): T |
| destructuring | Decompressione di data class | val (name, age) = person |
| typealias | Alias di tipo | typealias Orders = List<Order> |
| lateinit | Inizializzazione differita di var | lateinit var adapter: Adapter |
| lazy | Inizializzazione lazy di val | val config by lazy { load() } |
| delegated | Delega di proprietà | var x by Delegates.observable(0) |
reified — per API type-safe. lazy — per caricamento differito. delegated properties — per riutilizzare la logica delle proprietà. IT Sectr raccomanda di padroneggiare tutte queste funzionalità per uno sviluppo efficace in Kotlin.
Flow — flusso di dati asincrono freddo in Kotlin. Emette valori su richiesta del collettore. StateFlow — Flow caldo con un unico valore corrente. Usato in ViewModel per UI State. SharedFlow — Flow caldo per eventi (eventi una tantum). flowOf, asFlow — creazione di Flow da collezioni. catch, retry, debounce — operatori. stateIn, shareIn — conversione di Flow freddo in caldo. IT Sectr raccomanda StateFlow per UI State e SharedFlow per eventi (Snackbar, navigazione).
class SearchViewModel : ViewModel() {
private val _query = MutableStateFlow("")
val suggestions: StateFlow<List<String>> = _query
.debounce(300)
.filter { it.length >= 2 }
.flatMapLatest { repository.search(it) }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())
fun onQueryChanged(query: String) {
_query.value = query
}
}kotlinx.serialization — libreria Kotlin per la serializzazione JSON. @Serializable — annotazione. @SerialName — nome campo personalizzato. Supporta: JSON, CBOR, ProtoBuf. Parcelize — @Parcelize per Android Parcelable (senza implementazione manuale). Gson vs Moshi vs kotlinx: kotlinx.serialization — Kotlin-first, compile-safe, senza reflection. Moshi — annotazioni + codegen. IT Sectr raccomanda kotlinx.serialization per nuovi progetti e Moshi per quelli esistenti.
@Serializable
data class ApiResponse<T>(
val success: Boolean,
@SerialName("data") val data: T? = null,
val error: String? = null
)
@Serializable
data class User(
val id: Int,
val name: String,
val email: String
)
// Deserializzazione
val json = Json { ignoreUnknownKeys = true }
val response = json.decodeFromString<ApiResponse<List<User>>>(jsonString)
println("Users: ${response.data?.size ?: 0}")Domande Frequenti
data class — per dati (generazione automatica di equals/hashCode/copy). sealed class — per gerarchia di tipi (controllo in when). sealed interface — lo stesso con ereditarietà multipla.
let, run, with, apply, also. Si differenziano per contesto (it vs this) e valore restituito (result vs context). let — null safety, apply — configurazione, also — effetti collaterali.
CoroutineScope — un ambito per le coroutine. lifecycleScope — per Activity, viewModelScope — per ViewModel. GlobalScope — non raccomandato.
reified — preservazione del tipo nelle funzioni inline. Permette T::class e is T. Funziona solo con funzioni inline.
launch — senza risultato. async — con risultato (Deferred). runBlocking — ponte bloccante per main/test. withContext — cambio Dispatcher.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.