Kotlin specifics in mobile development: what it is, what constructs and how it works

Author: IT Sectr Published: 2026-06-29 Reading time: 11 min

Kotlin is the primary language for Android development. According to Google Android Docs (2025), over 95% of new Android projects use Kotlin. Understanding Kotlin specifics — data class, sealed class, coroutines and scope functions — is a mandatory requirement for an Android developer.

Key Takeaways

  • data class — automatic generation of equals/hashCode/toString/copy/componentN. For data models. sealed class — restricted type hierarchy with when checking.
  • Scope functions: let, run, with, apply, also. Differ by context (it vs this) and return value.
  • Coroutines: launch (fire-and-forget), async (with result), runBlocking (bridge), withContext (Dispatcher switch).
  • lifecycleScope and viewModelScope — Lifecycle-aware coroutines without manual cancellation.
  • reified — type preservation in inline functions. lateinit/lazy — deferred initialization.

Classes (data class, sealed class, object, companion object)

Kotlin extends class concepts from Java. data class, sealed class, object and companion object — constructs that don't exist in Java or are implemented differently.

data class vs sealed class

data class — a class that automatically generates equals(), hashCode(), toString(), copy() and componentN(). Ideal for data models (DTO, Entity). Requirements: at least one primary constructor parameter, val/var, cannot be open/sealed/inner. sealed class — a class with a restricted subclass hierarchy. All subclasses are known at compile time and declared in the same file. when expression with sealed class does not require an else branch. sealed interface (Kotlin 1.9+) — same as sealed class but allows multiple inheritance. object — a singleton, declared with the object keyword (not class). Thread-safe lazy initialization. companion object — static members of a class. Has a name (Companion by default). Can implement interfaces and have extension functions.

Type Description Usage
data classAutomatic generation of equals, hashCode, toString, copyData models, DTO, Entity
sealed classRestricted hierarchy, when checkingStates, Result, UI State
sealed interfacesealed class + multiple inheritanceEvents, Actions (Kotlin 1.9+)
objectSingleton (declarative)Factory, Utility, Constants
companion objectStatic class membersFactory Method, static constants
enum classEnumeration with constantsStates with a fixed set

data class — for 90% of models. sealed class — for UI State and Result. object — for singletons. IT Sectr recommends sealed class for all screen states (Loading, Success, Error).

Sealed class in practice

Sealed class — a powerful tool for modeling states. Example: UiState<T> with subclasses Loading, Success(data: T), Error(message: String). when expression guarantees handling all states. Sealed interface — for events and actions where multiple implementation is needed. Value class (Kotlin 1.5+) — a wrapper for a single value without overhead. Used for type-safe identifiers: @JvmInline value class UserId(val id: String).

Functions (extension, inline, higher-order, scope functions)

Extension Function — adding a method to an existing class without inheritance. fun String.isEmail(): Boolean. Extension Property — same for properties (without backing field). Inline Function — inlining the function body at the call site — no call overhead. Used for higher-order functions with lambdas. Higher-Order Function — a function that takes or returns another function. Scope Functions — five functions for working with object context: let, run, with, apply, also.

Scope Functions

let — context it, returns lambda result. Used for null-safe calls (?.let {}). apply — context this, returns context. For object configuration. run — context this, returns lambda result. For computations with context. also — context it, returns context. For side effects (logging). with — not an extension, context this, returns lambda result. For a group of operations on an object. Lambda — anonymous function. Destructuring Declaration — unpacking data class into variables: val (name, age) = person.

Inline + reified

Inline function with reified — the only way to preserve a generic type in JVM. Used for: type-safe builders (Gson.fromJson<T>()), type checking (is T), getting the class (T::class). Crossinline and Noinline — modifiers for lambda parameters in inline functions. crossinline — forbids non-local return, noinline — forbids inlining a specific lambda. IT Sectr recommends inline + reified only when working with types; for regular higher-order functions, inline can increase bytecode size.

Coroutines (Coroutine Builder, Dispatchers, Scope)

Coroutines — lightweight threads for asynchronous programming. They don't block the thread — they suspend. suspend function — a function that can be suspended without blocking the thread. Can only be called from a coroutine or another suspend function.

CoroutineScope

CoroutineScope — a scope for coroutines. Contains CoroutineContext (Job + Dispatcher). lifecycleScope — for Activity/Fragment (Lifecycle-aware). viewModelScope — for ViewModel (auto-cancellation on onCleared()). GlobalScope — global scope (not recommended for production — memory leaks). Dispatchers: Dispatchers.Main (UI), Dispatchers.IO (network/disk), Dispatchers.Default (CPU-intensive), Dispatchers.Unconfined (not recommended). launch — starts a coroutine: Job. async — starts with result: Deferred<T>. runBlocking — blocking bridge. withContext — switches Dispatcher inside a suspend function.

kotlin
// Example coroutines: loading data 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)
            }
        }
    }
}

// Parallel requests with 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 — standard coroutine launch in ViewModel. withContext(Dispatchers.IO) — switching to IO thread for network request. Dispatchers determine on which thread pool the coroutine executes. IT Sectr recommends viewModelScope for ViewModel and lifecycleScope for Activity/Fragment.

Advanced features (reified, destructuring, lateinit/lazy)

reified — a type modifier in inline functions. Allows using the type: T::class, is T, as T. Without reified, Generics in JVM are erased (type erasure). inline fun + reified — a powerful combination for type-safe APIs. Destructuring Declaration — val (x, y) = point. Works for data class and types with componentN(). typealias — type alias: typealias Callback = (String) -> Unit. lateinit — deferred var initialization (for dependency injection). Not thread-safe. lazy — lazy val initialization (thread-safe by default). lazy(LazyThreadSafetyMode.NONE) — without synchronization. Extension function and Extension property — adding functionality without inheritance. Kotlin is a language where extension functions solve 90% of utility tasks.

Delegated Properties

Delegated Properties — delegating getter/setter to another object. Standard delegates: lazy, observable, vetoable, map. Custom delegate via getValue/setValue operators. by — delegation keyword: val name by lazy { loadName() }. Delegated properties are the foundation for ViewModel delegates (by viewModels()). IT Sectr recommends lazy for deferred initialization and Delegates.observable for observing changes.

Feature Description Example
reifiedPreserving generic type in inlineinline fun <reified T> parse(): T
destructuringUnpacking data classval (name, age) = person
typealiasType aliastypealias Orders = List<Order>
lateinitDeferred var initializationlateinit var adapter: Adapter
lazyLazy val initializationval config by lazy { load() }
delegatedProperty delegationvar x by Delegates.observable(0)

reified — for type-safe APIs. lazy — for deferred loading. delegated properties — for reusing property logic. IT Sectr recommends mastering all these features for effective Kotlin development.

Flow and StateFlow

Flow — cold asynchronous data stream in Kotlin. Emits values on demand by the collector. StateFlow — hot Flow with a single current value. Used in ViewModel for UI State. SharedFlow — hot Flow for events (one-shot events). flowOf, asFlow — creating Flow from collections. catch, retry, debounce — operators. stateIn, shareIn — converting cold Flow to hot. IT Sectr recommends StateFlow for UI State and SharedFlow for events (Snackbar, navigation).

kotlin
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
    }
}

Serialization (kotlinx.serialization, Parcelize)

kotlinx.serialization — Kotlin library for JSON serialization. @Serializable — annotation. @SerialName — custom field name. Supports: JSON, CBOR, ProtoBuf. Parcelize — @Parcelize for Android Parcelable (without manual implementation). Gson vs Moshi vs kotlinx: kotlinx.serialization — Kotlin-first, compile-safe, without reflection. Moshi — annotations + codegen. IT Sectr recommends kotlinx.serialization for new projects and Moshi for existing ones.

kotlin
@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
)

// Deserialization
val json = Json { ignoreUnknownKeys = true }
val response = json.decodeFromString<ApiResponse<List<User>>>(jsonString)
println("Users: ${response.data?.size ?: 0}")

Frequently Asked Questions

What is the difference between data class and sealed class?

data class — for data (auto-generation of equals/hashCode/copy). sealed class — for type hierarchy (when checking). sealed interface — same with multiple inheritance.

What are scope functions in Kotlin?

let, run, with, apply, also. Differ by context (it vs this) and return value (result vs context). let — null safety, apply — configuration, also — side effects.

What is CoroutineScope and what types exist?

CoroutineScope — a scope for coroutines. lifecycleScope — for Activity, viewModelScope — for ViewModel. GlobalScope — not recommended.

What is reified in Kotlin?

reified — type preservation in inline functions. Allows T::class and is T. Only works with inline functions.

What are coroutine builders: launch, async, runBlocking?

launch — without result. async — with result (Deferred). runBlocking — blocking bridge for main/test. withContext — Dispatcher switching.

Summary

  • data class — for models. sealed class — for states. object — for singletons.
  • Scope functions: let (null-safe), apply (configuration), run (computations), also (logging).
  • Coroutines: launch (fire-and-forget), async (with result), withContext (Dispatcher switch).
  • viewModelScope — standard for ViewModel. lifecycleScope — for Activity/Fragment.
  • reified — type-safe inline functions. lateinit — DI, lazy — lazy initialization.
  • Extension functions — add functionality without inheritance.
  • Dispatchers: Main (UI), IO (network/disk), Default (CPU). Choose the right one.

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project