Pocket Studio Academy
HomePart 33.1

The old way vs the Compose way

Free lesson8 min read·3 questions

Android has had two completely different ways of putting things on a screen. Seeing what the old one felt like is the fastest way to understand why the new one is shaped the way it is.

The job every app has to do

You have an . Android has given your app a rectangle of screen. Now something has to appear in it.

For the first thirteen years of Android there was one way to do that. Since 2021 there is a second way, and it is not an improvement on the first one — it is the opposite approach. Google now recommends the new one for every new app, and it is what this whole course uses.

Both ways can build exactly the same screen. Here is the screen we are going to build twice: a number and a button that makes the number go up.

9:41▲ ▮
Score: 3
+1

The same screen, whichever way you build it.

Think of it like this

Imagine a scoreboard at a school sports day.

Way one. A person stands at the board with chalk. When a team scores, someone shouts the new number and the chalk-holder rubs out the old one and writes the new one. It works — as long as they hear every shout, rub out every old number, and never get distracted. Miss one and the board is now telling a lie, and nobody can tell just by looking whether it is right.

Way two. There is no chalk. You write the scores on a slip of paper and push it through a slot. A machine inside reprints the entire board from that slip, instantly, every time the slip changes. There is nothing to forget, because there is no "update the board" step at all. The board is simply a picture of the slip.

Way one is how Android used to work. Way two is .

Way one: describe the screen once, then edit it forever

The old approach is called the View system. You describe the screen in an XML file — a that lives in res/layout/:

res/layout/activity_main.xmlxml
1<LinearLayout
2    android:orientation="vertical"
3    android:layout_width="match_parent"
4    android:layout_height="match_parent">
5
6    <TextView
7        android:id="@+id/scoreText"
8        android:layout_width="wrap_content"
9        android:layout_height="wrap_content"
10        android:text="Score: 0" />
11
12    <Button
13        android:id="@+id/addButton"
14        android:layout_width="wrap_content"
15        android:layout_height="wrap_content"
16        android:text="+1" />
17
18</LinearLayout>

That file is a starting position. It says what the screen looks like at the moment it is created and nothing more. To make anything ever change, you write that reaches into the screen and edits it:

MainActivity.kt — the old waykotlin
1var score = 0
2
3override fun onCreate(state: Bundle?) {
4    super.onCreate(state)
5    setContentView(R.layout.activity_main)
6
7    val scoreText =
8        findViewById<TextView>(R.id.scoreText)
9    val addButton =
10        findViewById<Button>(R.id.addButton)
11
12    addButton.setOnClickListener {
13        score = score + 1
14        scoreText.text = "Score: $score"
15    }
16}

Read that last block carefully, because the problem is hiding in plain sight.

There are now two copies of the score. One is the score variable in your code. The other is the text sitting inside scoreText on the screen. They are separate things, and the only reason they ever agree is that line scoreText.text = "Score: $score", which you had to remember to write.

Forget it in one place out of twenty and you get the worst kind of bug: the app is right, the screen is wrong, and nothing crashes. This style is called imperative UI — you issue orders, one at a time, and the screen obeys each one.

Way two: describe the screen as a function of the data

Compose deletes the XML file and deletes findViewById. Instead you write a function that describes what should be on screen for the data you have right now:

MainActivity.kt — the Compose waykotlin
1@Composable
2fun ScoreCounter() {
3    var score by remember { mutableStateOf(0) }
4
5    Column(
6        modifier = Modifier.padding(24.dp),
7        horizontalAlignment =
8            Alignment.CenterHorizontally
9    ) {
10        Text(text = "Score: $score")
11        Button(onClick = { score++ }) {
12            Text("+1")
13        }
14    }
15}

Nine lines, one file, one copy of the score.

That is the whole idea, and it is worth saying in one sentence:

You never update the screen. You change the data, and the screen is a description of the data.

This style is called declarative. You declare what should be true; the system works out what to change on the glass. It is the same trick a spreadsheet plays. You do not tell cell C1 to redraw when A1 changes — you write =A1*2 once, and it just keeps being correct.

What you actually gain

The old wayCompose
XML file and Kotlin fileOne Kotlin file
Two copies of every changing valueOne copy
You remember to update the screenCompose updates it
Reuse means a custom View classReuse means calling a function
A bug means "the display is out of date"That bug category does not exist

The reuse row matters more than it looks. In the old system, making a reusable piece of screen — say a player's score panel — meant writing a whole class, and most people did not bother, so layouts got copy-pasted. In Compose a reusable piece of screen is a function, and you already know how to write functions. You will make dozens.

Note

The View system is not dead. Millions of apps still use it, and Android itself is still built on it underneath — Compose ultimately draws into a single old-style View. But nothing in this course uses XML , and if you start a new app in 2026, neither should you.

Where Compose plugs into your app

You already met MainActivity in Part 2. Here it is in a Compose app, complete:

MainActivity.ktkotlin
1class MainActivity : ComponentActivity() {
2    override fun onCreate(state: Bundle?) {
3        super.onCreate(state)
4        setContent {
5            ScoreCounter()
6        }
7    }
8}

setContent { } is the doorway. Everything inside those braces is Compose; everything outside is ordinary Android. One , one setContent, and from there down it is all just functions calling functions.

Notice what is missing: no setContentView, no R.layout anything, no to wire views to variables. That is roughly two hundred lines you will never write.

Try it in Pocket Studio

No typing this time — this is a two-minute look at real code.

  1. Open Pocket Studio and tap Projects.
  2. Open the project you built in Part 0.
  3. In the file tree, open app/src/main/java/…/MainActivity.kt.
  4. Find the line that says setContent {. Everything indented under it is Compose.
  5. Now look at the file tree again and open app/src/main/res/. Look for a folder called layout. There isn't one. That is the clearest single sign that this is a Compose app.
  6. Tap the Run button (the triangle) once, just to confirm the project still builds. Then come back — Lesson 3.2 starts here.
Error Doctor4 common errors
e: Unresolved reference: setContent
MeansKotlin cannot find setContent. It is not built into ComponentActivity — it arrives with the activity-compose library and needs its own import.
FixAdd import androidx.activity.compose.setContent at the top of the file. If it still fails, check that app/build.gradle.kts contains implementation(libs.androidx.activity.compose).
e: Unresolved reference: R
MeansYou are following an old tutorial that used setContentView(R.layout.activity_main). Your project has no res/layout folder, so there is no generated R.layout entry to point at.
FixDelete the setContentView(...) line and use setContent { ... } instead. A Compose project does not have layout XML at all.
AAPT: error: resource layout/activity_main not found.
MeansThe build tool was asked for an XML layout that does not exist in this project — the same mistake as above, caught one stage later by the resource packer instead of by Kotlin.
FixRemove every reference to R.layout.*. In Compose the screen is described by a Kotlin function, not by a resource file.
e: Unresolved reference: Text
MeansText is a composable supplied by Material 3, and Pocket Studio has not imported it for you yet.
FixAdd import androidx.compose.material3.Text at the top of the file. Almost every Compose error in your first week is a missing import — get comfortable with them now.
Recap
  • The old View system is imperative: an XML plus Kotlin that reaches in and edits the screen with findViewById. Every changing value exists twice.
  • is declarative: a Kotlin function describes the screen for the data you have, and Compose keeps the glass matching the description.
  • You never write "now update the screen". You change the data.
  • A reusable piece of screen is just a function, so reuse costs almost nothing.
  • setContent { } inside your is where Compose begins.
  • Next: writing your own composable function from scratch, and seeing it appear on your phone.