Jetpack Compose with Kotlin is the way to build your first Android screen in 2026—skip XML entirely. This guide walks Tamil Nadu developers through the Kotlin you actually need, how a @Composable WelcomeScreen replaces activity_main.xml, and how state plus recomposition redraw only what changed. You will also see LazyColumn for lists, NavHost for screens, and why Indian product teams already interview on this stack.
- Kotlin plus Jetpack Compose is the native Android UI stack. XML layouts are legacy.
- A screen is a @Composable function, not an XML file plus findViewById.
- When state changes, Compose redraws only what depends on that state. That is recomposition.
- Lists go in LazyColumn. Moving between screens is a NavHost, not a pile of Intents on day one.
- Indian product teams and interviews already expect this stack.
What is Kotlin plus Jetpack Compose, in one line?
Kotlin is the language. Jetpack Compose is how you draw the screen.
Put them together and you get native Android without XML layouts. You write functions. Those functions become UI. A new Android Studio project already starts in this world. You are not waiting for some future stack to land.
Picture a Java Android person in a Tidel Park bay. They open a fresh module. There is no activity_main.xml. There is a setContent block and a Greeting function. That is Compose. If the kotlin android tutorial you bookmarked still begins with LinearLayout, park it. Those notes will fight you.
If you already know Java, which Kotlin bits do you need first?
You do not need the whole language. You need the bits that show up in every Compose file.
val is a final variable. var can change. A data class is your old POJO, minus the getter noise. Default arguments mean you stop writing three constructors. String templates replace the plus-sign mess. name: String cannot be null. name: String? can. The compiler will nag you. That nagging is the feature.
Functions are values. You will pass onClick: () -> Unit the way you used to pass a click listener. Trailing lambdas make Button(onClick = { ... }) read like English.
data class User(val name: String, val city: String = "Chennai")
fun greet(user: User): String {
return "Hi ${user.name}, welcome from ${user.city}"
}
fun main() {
val user = User(name = "Priya")
println(greet(user))
}Run that in a scratch file. If this feels comfortable, you can read Compose. If it does not, pause. Write-ups that skip Kotlin are why people bounce on day two.
How do you draw a screen with composables?
A composable is a function with @Composable on top. You do not return a View. You call other composables inside it: Text, Button, Column, Row. Compose builds a tree. The system paints that tree.
Column is a vertical stack. Row is horizontal. Modifier is how you add padding, size, clicks. Think of Modifier as the layout params you used to stuff into XML, except it chains.
@Composable
fun WelcomeScreen(name: String) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(24.dp)
) {
Text(
text = "Vanakkam, $name",
style = MaterialTheme.typography.headlineMedium
)
Text(text = "This screen has no XML file.")
}
}Call WelcomeScreen(name = "Arun") from setContent in MainActivity. That is your first native screen. MaterialTheme here is Material 3, which the current project template already wires. Do not bolt on an old AppCompat XML theme unless you enjoy debugging colours at 1 a.m.
Keep composables small. One screen function, a few child functions. Name them after what the user sees, not after the widget type.
How do state and recomposition actually work?
State is the data that should change the screen when it changes. A counter. A text field. A selected tab.
You hold it with remember { mutableStateOf(0) }. remember keeps the value across redraws. mutableStateOf tells Compose to watch it. The by keyword means you write count++ instead of count.value++.
Recomposition is Compose calling your function again with the new value. It is not Activity.recreate(). It is cheaper, and it only refreshes the bits that read that state.
@Composable
fun CounterScreen() {
var count by remember { mutableStateOf(0) }
Column(modifier = Modifier.padding(24.dp)) {
Text(text = "Taps: $count")
Button(onClick = { count++ }) {
Text("Add one")
}
}
}Tap the button. count changes. Text updates. You never called setText. That is the mental switch from XML.
If the phone rotates, remember dies with the Activity. Use rememberSaveable for a typed name or a tab index. Bigger data still lives in a ViewModel. Compose observes it. Do not stuff API calls inside the composable body.
How do lists and navigation work in Compose?
RecyclerView is not your first stop. LazyColumn draws only the rows on screen. You pass a list. You describe one row. Compose handles the recycling.
@Composable
fun CityList(
cities: List<String>,
onCityClick: (String) -> Unit
) {
LazyColumn {
items(cities) { city ->
Text(
text = city,
modifier = Modifier
.fillMaxWidth()
.clickable { onCityClick(city) }
.padding(16.dp)
)
}
}
}Need a second screen? Use Navigation Compose. You get a rememberNavController(), a NavHost, and a route. startDestination is home. navigate("cities") pushes. popBackStack() goes back. Intents are for other apps. Inside your own app, the nav graph is enough for the first week.
This is also where Indian companies actually live. A UPI history list, a Flipkart-style product row, a food-app restaurant card - that is LazyColumn plus a detail screen. In interviews in Chennai, Bengaluru, and Hyderabad, the take-home is often that shape. They will not ask you to hand-write a RelativeLayout.
What does it cost to run this on a phone?
Money: zero. Android Studio is free. The Kotlin toolchain is free. A Compose project template is one click in the wizard.
Time is the real bill. Install Studio. Let it download the SDK. Turn on USB debugging. On Windows you may fight a driver. On a Jio fiber line the first SDK fetch is slow. It is not broken. Go get tea.
| Option | Cost | Use it when |
|---|---|---|
| Android Emulator | Free | Daily coding, no cable |
| Your own phone | You already paid for it | Touch, notifications, real speed |
| Play Console internal testing | Free | A tester needs an installable build |
The emulator works. A mid-range phone works better for touch and jank. Plug in, accept the RSA prompt, click Run. If Gradle sync fails in an office network, check the proxy first. That is not a Compose bug.
Which mistakes get people into trouble?
Holding UI state in a plain var, without remember and mutableStateOf, is the classic one. You tap. Nothing moves. Compose never heard the change.
If you use the by keyword and forget import androidx.compose.runtime.getValue and setValue, the project will not compile. The error looks rude. The fix is two imports.
Network calls inside the composable body re-fire on every recomposition. Move that work to a ViewModel. Show a loading flag as state.
Do not reach for an Adapter. Do not call findViewById. If those names appear in a new screen, you slipped into the XML years. LazyColumn's items function needs the import from androidx.compose.foundation.lazy. The wrong items and you get a mysterious red line.
Hardcoded English strings will bite you when product asks for Tamil or Hindi. Use string resources even in a small demo if you can. And do not mash one ComposeView into a huge XML Activity on day one. Learn one full screen in Compose first.
What should you do now?
Open Android Studio. New project. Empty Activity with Compose. Get WelcomeScreen onto a phone tonight. Then do the practice task below. Do not open a second tutorial until this runs.
Build a list of five Chennai areas: T. Nagar, Adyar, Velachery, Anna Nagar, Tambaram. Put them in a LazyColumn. Tap a row and navigate to a detail screen that shows the area name in a large Text. Add a way back with popBackStack. No API. No database. No extra libraries.
If that build installs on your device, you have the first native Android screen that product teams in India actually want to see. XML can wait in the legacy folder.




Comments (0)
Be the first to comment!