Module 1: Kotlin and Android Basics
Kotlin Essentials for Android
Kotlin is the language Google recommends for Android development, and nearly all modern Android documentation, samples and libraries assume you know it. You do not need to master every corner of the language before building apps, but you do need a firm grip on a handful of features that appear in every screen you write: values and variables, null safety, functions and lambdas, classes and collections. This lesson gives you exactly that toolkit.
Values, variables and types
Kotlin has two ways to declare a name. Use val for a value that will not be reassigned and var for one that will. Prefer val by default; it makes code easier to reason about because fewer things can change behind your back. Kotlin infers types, so you rarely need to write them, but you can when it helps readability.
val shopName = "Mama Njeri Groceries" // String, inferred
var itemsInCart = 0 // Int, can change
val vatRate: Double = 0.16 // hypothetical rate, explicit type
itemsInCart += 3Strings support templates: "You have $itemsInCart items" or "Total: ${price * qty}" for expressions. This replaces most string concatenation.
Null safety
A large class of crashes in older Android apps came from using a reference that was null. Kotlin builds nullability into the type system. A String can never be null; a String? can. The compiler forces you to deal with the possibility before you use it.
var phone: String? = null
val length1 = phone?.length // safe call: null if phone is null
val length2 = phone?.length ?: 0 // Elvis operator: default value
if (phone != null) {
println(phone.length) // smart cast: compiler knows it is not null here
}
val risky = phone!!.length // throws if null: avoid thisUse the safe call ?. and the Elvis operator ?: freely. Treat !! as a warning sign: it says "crash here if I am wrong".
Functions, lambdas and data classes
Functions are declared with fun. Parameters can have default values and can be passed by name, which makes calls self-documenting. Single-expression functions can use = instead of a block.
fun formatPrice(amount: Double, currency: String = "KES"): String =
"$currency ${"%,.2f".format(amount)}"
formatPrice(1250.0) // "KES 1,250.00"
formatPrice(amount = 9.99, currency = "USD")
data class Product(val id: Int, val name: String, val price: Double, val stock: Int)A data class automatically gets equals, hashCode, toString and copy. You will use data classes constantly to describe UI state and data from databases or APIs. Because their properties are usually val, you change them by making a modified copy: product.copy(stock = product.stock - 1).
Lambdas are blocks of code you can pass around. Android APIs, especially Jetpack Compose, are full of them: onClick = { counter++ }. When the last parameter of a function is a lambda, you can write it outside the parentheses, which is why Compose code looks the way it does.
Working with collections
Kotlin distinguishes read-only collections (List, Map, Set) from mutable ones (MutableList and so on). The standard library gives you expressive functions that replace most manual loops.
val products = listOf(
Product(1, "Unga 2kg", 210.0, 14),
Product(2, "Sugar 1kg", 180.0, 0),
Product(3, "Cooking oil 1L", 390.0, 6)
)
val inStock = products.filter { it.stock > 0 }
val names = inStock.map { it.name }
val stockValue = products.sumOf { it.price * it.stock }
val cheapest = products.minByOrNull { it.price }
val byAvailability = products.groupBy { it.stock > 0 }Inside a single-parameter lambda, it refers to the parameter. Chaining filter, map and sumOf reads almost like a sentence and is the style you will see in Android codebases.
Worked example: a small cart calculation
Imagine a shop app where a cart holds product IDs and quantities. You want the total, skipping unknown IDs safely.
val catalogue = products.associateBy { it.id } // Map<Int, Product>
val cart = mapOf(1 to 2, 3 to 1, 99 to 5) // id to quantity
val total = cart.entries.sumOf { (id, qty) ->
val product = catalogue[id] ?: return@sumOf 0.0 // unknown id contributes nothing
product.price * qty
}
println(formatPrice(total)) // KES 810.00Notice how null safety is doing real work: catalogue[id] returns Product?, and the Elvis operator handles the missing item without a crash.
Common mistakes to avoid
- Using
vareverywhere. Start withvaland only switch when you genuinely need reassignment. - Sprinkling
!!to silence the compiler. Each one is a potential crash. Handle the null case instead. - Mutating shared lists. Exposing a
MutableListfrom a class lets any caller change it. Expose a read-onlyList. - Using
Doublefor money in serious financial code. Floating point can produce rounding errors. For learning it is fine, but production finance apps often store amounts as whole cents in aLongor useBigDecimal.
Exercise
Open the Kotlin Playground in your browser (play.kotlinlang.org) or a scratch file in Android Studio. Create a data class Expense with a description, amount and category, then build a list of at least six expenses. Use filter, groupBy and sumOf to print the total spent per category and the single largest expense. Finally add a nullable notes field and print each note, showing "No notes" when it is null without using !!.
Key points
- Prefer val over var, and let the compiler infer types where it stays readable
- Nullable types (String?) plus ?. and ?: prevent most null-pointer crashes
- Data classes and copy() are the standard way to model app data and UI state
- Collection functions like filter, map and sumOf replace most manual loops