Kotlin jest głównym językiem do programowania Androida. Według Google Android Docs (2025), ponad 95% nowych projektów na Androida używa Kotlina. Zrozumienie specyfiki Kotlina — data class, sealed class, korutyny i scope functions — jest obowiązkowym wymogiem dla programisty Androida.
Najważniejsze
Kotlin rozszerza koncepcje klas z Javy. data class, sealed class, object i companion object — konstrukcje, które nie istnieją w Javie lub są zaimplementowane inaczej.
data class — klasa automatycznie generująca equals(), hashCode(), toString(), copy() i componentN(). Idealna dla modeli danych (DTO, Entity). Wymagania: co najmniej jeden parametr w konstruktorze głównym, val/var, nie może być open/sealed/inner. sealed class — klasa z ograniczoną hierarchią podklas. Wszystkie podklasy są znane w czasie kompilacji i zadeklarowane w tym samym pliku. Wyrażenie when z sealed class nie wymaga gałęzi else. sealed interface (Kotlin 1.9+) — to samo co sealed class, ale pozwala na wielodziedziczenie. object — singleton, deklarowany słowem kluczowym object (nie class). Bezpieczna wątkowo leniwa inicjalizacja. companion object — statyczne elementy klasy. Ma nazwę (domyślnie Companion). Może implementować interfejsy i mieć extension functions.
| Typ | Opis | Zastosowanie |
|---|---|---|
| data class | Automatyczne generowanie equals, hashCode, toString, copy | Modele danych, DTO, Entity |
| sealed class | Ograniczona hierarchia, sprawdzanie when | Stany, Wynik, UI State |
| sealed interface | sealed class + wielodziedziczenie | Zdarzenia, Akcje (Kotlin 1.9+) |
| object | Singleton (deklaratywny) | Factory, Utility, Stałe |
| companion object | Statyczne elementy klasy | Factory Method, statyczne stałe |
| enum class | Wyliczenie ze stałymi | Stany ze stałym zestawem |
data class — dla 90% modeli. sealed class — dla UI State i Wyniku. object — dla singletonów. IT Sectr zaleca sealed class dla wszystkich stanów ekranu (Loading, Success, Error).
Sealed class — potężne narzędzie do modelowania stanów. Przykład: UiState<T> z podklasami Loading, Success(data: T), Error(message: String). Wyrażenie when gwarantuje obsługę wszystkich stanów. Sealed interface — dla zdarzeń i akcji, gdzie potrzebna jest wielokrotna implementacja. Value class (Kotlin 1.5+) — opakowanie dla pojedynczej wartości bez narzutu. Używane do bezpiecznych typowo identyfikatorów: @JvmInline value class UserId(val id: String).
Extension Function — dodanie metody do istniejącej klasy bez dziedziczenia. fun String.isEmail(): Boolean. Extension Property — to samo dla właściwości (bez backing field). Inline Function — wstawienie ciała funkcji w miejscu wywołania — bez narzutu wywołania. Używane dla funkcji higher-order z lambdami. Higher-Order Function — funkcja przyjmująca lub zwracająca inną funkcję. Scope Functions — pięć funkcji do pracy z kontekstem obiektu: let, run, with, apply, also.
let — kontekst it, zwraca wynik lambdy. Używane do wywołań null-safe (?.let {}). apply — kontekst this, zwraca kontekst. Do konfiguracji obiektu. run — kontekst this, zwraca wynik lambdy. Do obliczeń z kontekstem. also — kontekst it, zwraca kontekst. Do efektów ubocznych (logowanie). with — nie jest extension, kontekst this, zwraca wynik lambdy. Do grupy operacji na obiekcie. Lambda — funkcja anonimowa. Destructuring Declaration — rozpakowanie data class na zmienne: val (name, age) = person.
Inline function z reified — jedyny sposób zachowania typu generycznego w JVM. Używane do: bezpiecznych typowo builderów (Gson.fromJson<T>()), sprawdzania typów (is T), pobierania klasy (T::class). Crossinline i Noinline — modyfikatory parametrów lambda w funkcjach inline. crossinline — zabrania non-local return, noinline — zabrania inline'owania konkretnej lambdy. IT Sectr zaleca inline + reified tylko podczas pracy z typami; dla zwykłych funkcji higher-order, inline może zwiększyć rozmiar bytecodu.
Korutyny — lekkie wątki do programowania asynchronicznego. Nie blokują wątku — zawieszają się (suspend). suspend function — funkcja, którą można zawiesić bez blokowania wątku. Może być wywołana tylko z korutyny lub innej suspend function.
CoroutineScope — zakres korutyn. Zawiera CoroutineContext (Job + Dispatcher). lifecycleScope — dla Activity/Fragment (Lifecycle-aware). viewModelScope — dla ViewModel (automatyczne anulowanie przy onCleared()). GlobalScope — globalny zakres (nie używać w produkcji — wycieki pamięci). Dispatchers: Dispatchers.Main (UI), Dispatchers.IO (sieć/dysk), Dispatchers.Default (CPU-intensive), Dispatchers.Unconfined (niezalecane). launch — uruchomienie korutyny: Job. async — uruchomienie z wynikiem: Deferred<T>. runBlocking — blokujący most. withContext — zmiana Dispatcher wewnątrz suspend function.
// Przykład korutyn: ładowanie danych w 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)
}
}
}
}
// Równoległe żądania z 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 — standardowe uruchomienie korutyny w ViewModel. withContext(Dispatchers.IO) — przełączenie na wątek IO dla żądania sieciowego. Dispatchers określają, na której puli wątków wykonuje się korutyna. IT Sectr zaleca viewModelScope dla ViewModel i lifecycleScope dla Activity/Fragment.
reified — modyfikator typu w funkcjach inline. Pozwala użyć typu: T::class, is T, as T. Bez reified, generyki w JVM są wymazywane (type erasure). inline fun + reified — potężna kombinacja dla bezpiecznych typowo API. Destructuring Declaration — val (x, y) = point. Działa dla data class i typów z componentN(). typealias — alias typu: typealias Callback = (String) -> Unit. lateinit — opóźniona inicjalizacja var (dla dependency injection). Niebezpieczny wątkowo. lazy — leniwa inicjalizacja val (domyślnie bezpieczna wątkowo). lazy(LazyThreadSafetyMode.NONE) — bez synchronizacji. Extension function i Extension property — dodawanie funkcjonalności bez dziedziczenia. Kotlin to język, w którym extension functions rozwiązują 90% zadań narzędziowych.
Delegated Properties — delegowanie getter/setter do innego obiektu. Standardowe delegaty: lazy, observable, vetoable, map. Niestandardowy delegat przez operatory getValue/setValue. by — słowo kluczowe delegacji: val name by lazy { loadName() }. Delegowane właściwości są podstawą delegatów ViewModel (by viewModels()). IT Sectr zaleca lazy do opóźnionej inicjalizacji i Delegates.observable do obserwowania zmian.
| Funkcja | Opis | Przykład |
|---|---|---|
| reified | Zachowanie typu generycznego w inline | inline fun <reified T> parse(): T |
| destructuring | Rozpakowanie data class | val (name, age) = person |
| typealias | Alias typu | typealias Orders = List<Order> |
| lateinit | Opóźniona inicjalizacja var | lateinit var adapter: Adapter |
| lazy | Leniwa inicjalizacja val | val config by lazy { load() } |
| delegated | Delegowanie właściwości | var x by Delegates.observable(0) |
reified — dla bezpiecznych typowo API. lazy — dla opóźnionego ładowania. delegated properties — do ponownego wykorzystania logiki właściwości. IT Sectr zaleca opanowanie wszystkich tych funkcji dla efektywnego programowania w Kotlinie.
Flow — zimny asynchroniczny strumień danych w Kotlinie. Emituje wartości na żądanie kolektora. StateFlow — gorący Flow z pojedynczą bieżącą wartością. Używany w ViewModel dla UI State. SharedFlow — gorący Flow dla zdarzeń (zdarzenia jednorazowe). flowOf, asFlow — tworzenie Flow z kolekcji. catch, retry, debounce — operatory. stateIn, shareIn — konwersja zimnego Flow na gorący. IT Sectr zaleca StateFlow dla UI State i SharedFlow dla zdarzeń (Snackbar, nawigacja).
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 — biblioteka Kotlin do serializacji JSON. @Serializable — adnotacja. @SerialName — niestandardowa nazwa pola. Obsługuje: JSON, CBOR, ProtoBuf. Parcelize — @Parcelize dla Android Parcelable (bez ręcznej implementacji). Gson vs Moshi vs kotlinx: kotlinx.serialization — Kotlin-first, bezpieczny kompilacyjnie, bez refleksji. Moshi — adnotacje + codegen. IT Sectr zaleca kotlinx.serialization dla nowych projektów i Moshi dla istniejących.
@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
)
// Deserializacja
val json = Json { ignoreUnknownKeys = true }
val response = json.decodeFromString<ApiResponse<List<User>>>(jsonString)
println("Users: ${response.data?.size ?: 0}")Często zadawane pytania
data class — dla danych (automatyczne generowanie equals/hashCode/copy). sealed class — dla hierarchii typów (sprawdzanie w when). sealed interface — to samo z wielodziedziczeniem.
let, run, with, apply, also. Różnią się kontekstem (it vs this) i wartością zwracaną (result vs context). let — null safety, apply — konfiguracja, also — efekty uboczne.
CoroutineScope — zakres korutyn. lifecycleScope — dla Activity, viewModelScope — dla ViewModel. GlobalScope — niezalecany.
reified — zachowanie typu w funkcjach inline. Pozwala na T::class i is T. Działa tylko z funkcjami inline.
launch — bez wyniku. async — z wynikiem (Deferred). runBlocking — blokujący most dla main/test. withContext — zmiana Dispatcher.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.