AI Computer Institute
Expert-curated CS & AI curriculum aligned to CBSE standards. A bharath.ai initiative. About Us

Android Development Basics: Building Apps for Billions of Users

📚 Mobile Development⏱️ 21 min read🎓 Grade 9
✍️ AI Computer Institute Editorial Team Updated: August 2026 CBSE-aligned · Peer-reviewed · 21 min read
Content curated by subject matter experts with IIT/NIT backgrounds. All chapters are fact-checked against official CBSE/NCERT syllabi.

Open any phone in an Indian household and you will find the same handful of icons repeated: a messaging app, a UPI payment app, IRCTC for train tickets, a cricket score app. Every one of those icons is an Android app, and Android runs on the large majority of smartphones sold in India. When you tap "Pay" in a UPI app, something very specific happens in a very specific order — a piece of code notices your tap, reads the amount you typed, and changes what is drawn on your screen. That entire chain of events, from finger to pixel, is what this chapter teaches you to build, understand, and trace line by line.

Most students' first guess about how an app works is wrong in a useful way: they imagine it as one continuous block of instructions, like a school notice read out top to bottom. Android apps do not run like that. They sit idle, doing nothing, until something happens — a tap, a notification, a timer — and then a small piece of code wakes up, does its job, and goes back to sleep. This is called event-driven programming, and it is the single biggest mental shift you need to make to understand Android development. Everything else in this chapter builds on it.

An App Is Not a Website Wearing a Disguise

A common misconception is that an Android app is "just a website without the address bar." This is incorrect, and the distinction matters for how you write code. A website runs inside a browser, which translates HTML and JavaScript into pixels on demand, and it typically needs an internet connection to function at all. A native Android app, which is what this chapter teaches, is compiled ahead of time into a format the phone's processor and Android's runtime can execute directly. It is written in Kotlin (the language Google now recommends) or Java, and it talks straight to Android's own APIs for the camera, GPS, contacts, and storage — no browser in between. This is why a native app can work fully offline, respond to a tap in milliseconds, and access hardware a website cannot touch, while also meaning you need a separate codebase for Android versus iPhone unless you deliberately choose a cross-platform toolkit. Some apps do embed a "WebView" — a mini browser — inside a native shell, and it is fair to call those hybrid, but the default, and the one this chapter builds, is fully native.

Underneath every Android app sits a stack of layers, and knowing they exist explains a lot of Android's behaviour. At the very bottom is the Linux kernel, which manages memory, processes, and talks to hardware drivers. Above that sit native C/C++ libraries and the Android Runtime (ART), which is what actually executes your compiled Kotlin code on the device. Above that is the Java/Kotlin API framework — the set of classes like Activity, Button, and TextView that you write code against. Your app sits at the very top, alongside every other app, each isolated from the others by the operating system so that one crashing app cannot normally take down the whole phone. You will not write kernel code in this chapter, but knowing this stack exists explains why, for instance, an app can freeze without freezing your calls or your WhatsApp messages — they are separate, sandboxed processes.

The Two Halves of Every Android Screen

Every screen you build in Android is split into two files that do two completely different jobs, and confusing their roles is the second most common beginner mistake. The first file is a layout, written in a markup language called XML. It declares what exists on screen — a button here, a text box there — the way a stage manager's diagram marks where the chairs and props go before a play, without saying a word about what the actors do. The second file is your Kotlin code, an Activity class, which is the actor's script — it decides what happens when the audience (the user) interacts with something on that stage.

This separation is deliberate and useful. A translator can rewrite every word of text in the XML layout to Hindi or Tamil without touching a single line of your logic. A designer can move the button from the top of the screen to the bottom by editing only the XML. Meanwhile, the Kotlin file never needs to know or care what colour the button is — it only needs to know the button exists and that something should happen when it is tapped. Keeping "what it looks like" and "what it does" in separate files is a form of the same idea you may already know from writing Python functions: separating data from the logic that processes it.

Building a Real App: A Cricket Run Rate Calculator

Let's build something concrete: an app that takes runs scored and overs faced, and calculates the run rate — the same number shown on the broadcast screen during a match, calculated simply as runs divided by overs. This app needs two text boxes for input, a button to trigger the calculation, and a text label to show the result. Here is the layout file, activity_main.xml, which declares those four elements:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <EditText
        android:id="@+id/etRuns"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Runs scored"
        android:inputType="number" />

    <EditText
        android:id="@+id/etOvers"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Overs faced (e.g. 20.0)"
        android:inputType="numberDecimal" />

    <Button
        android:id="@+id/btnCalculate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Calculate Run Rate" />

    <TextView
        android:id="@+id/tvResult"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:paddingTop="16dp" />

</LinearLayout>

Read this the way you would read a seating chart, not a program. LinearLayout is a container that stacks its children vertically because of android:orientation="vertical". Each child element — EditText, Button, TextView — is given an android:id, which is the label your Kotlin code will use later to find that exact element among possibly dozens on the screen. Notice android:inputType="number" on the runs field: this tells Android to show a numeric keyboard instead of a full alphabet keyboard when the user taps that box — a small detail that real apps get right and careless ones don't.

Wiring the Button: Kotlin Code Line by Line

The XML file above draws four shapes on a screen that do nothing. Nothing happens when you tap the button yet, because no code has been told to listen for that tap. That is the job of MainActivity.kt:

package com.aici.runratecalculator

import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val etRuns = findViewById<EditText>(R.id.etRuns)
        val etOvers = findViewById<EditText>(R.id.etOvers)
        val btnCalculate = findViewById<Button>(R.id.btnCalculate)
        val tvResult = findViewById<TextView>(R.id.tvResult)

        btnCalculate.setOnClickListener {
            val runs = etRuns.text.toString().toDouble()
            val overs = etOvers.text.toString().toDouble()
            val runRate = runs / overs
            tvResult.text = "Run Rate: %.2f".format(runRate)
        }
    }
}

Trace this exactly the way the Android system does. MainActivity extends AppCompatActivity, which is Android's base class for a single screen. The method onCreate() is called automatically by the system, exactly once, the moment this screen is first built — you never call it yourself. Inside it, setContentView(R.layout.activity_main) tells this Kotlin class which XML file to use as its stage; R is a class Android generates automatically that contains a reference to every id you declared in XML, so R.layout.activity_main and R.id.etRuns are not magic strings — they are compiler-checked references, and a typo there fails to compile rather than crashing silently at runtime.

The four findViewById calls each reach into the XML layout and hand back the actual on-screen object with that id, stored in a variable so the code can refer to it. Nothing inside setOnClickListener { ... } runs yet at this point — onCreate() only registers this block as "the code to run later, when a tap happens," then finishes. The app now sits idle. This is the event-driven idea from the opening section made concrete: the block of code between the curly braces is asleep until the user acts.

Tracing the App With Real Numbers

Suppose a team has scored 180 runs in 20 overs, and the user types 180 into the runs box and 20 into the overs box, then taps the button. Here is exactly what the listener block does, in order:

  1. etRuns.text holds the characters the user typed, as a CharSequence; .toString() converts that to the plain text string "180".
  2. .toDouble() parses that string of characters into the numeric value 180.0, and this is stored in the variable runs.
  3. The same happens to the overs box: "20" becomes 20.0, stored in overs.
  4. runRate is computed as 180.0 / 20.0, which evaluates to 9.0.
  5. "Run Rate: %.2f".format(9.0) formats that number to exactly two decimal places, producing the text "Run Rate: 9.00".
  6. tvResult.text is set to that string, and Android redraws the screen to show it.

Every one of those six steps is ordinary, traceable logic — no different in kind from a Python function that takes two inputs and returns a computed output. The only genuinely new idea is step zero, invisible in the trace above: none of this ran until the user's tap triggered it.

The Event Flow, Visualised

The diagram below shows the complete path from a physical tap to a redrawn screen for this exact app, colour-coded by which file is responsible: blue boxes are declared in the XML layout, amber boxes are Kotlin code executing.

Declared in activity_main.xml (the UI) Runs in MainActivity.kt (the logic) Screen shows Button "Calculate Run Rate" declared as android:id="@+id/btnCalculate" user taps Android delivers a touch event to MainActivity btnCalculate.setOnClickListener { ... } block wakes up and starts running Reads etRuns.text "180" and etOvers.text "20" converts each with .toDouble() Computes runRate = runs / overs 180.0 / 20.0 = 9.0 Sets tvResult.text = "Run Rate: 9.00" Screen redraws: TextView now shows "Run Rate: 9.00"

Notice that the diagram starts and ends inside the blue "declared in XML" layer, with five amber "Kotlin logic" steps sandwiched in between. This is the shape of essentially every interactive Android screen you will ever build: idle UI, a triggering event, a short burst of code, updated UI.

A Common Misconception: "Division Always Gives a Decimal"

Here is a mistake almost every beginner makes at least once, and it is worth naming precisely because it produces a wrong answer with no error message. Suppose a student writes the input-reading lines like this instead:

val runs = etRuns.text.toString().toInt()
val overs = etOvers.text.toString().toInt()
val runRate = runs / overs

For runs = 163 and overs = 20, a student expects 163 / 20 = 8.15. But because both runs and overs were parsed with .toInt(), they are whole numbers (type Int), and in Kotlin — as in Java, C, and C++ — dividing an Int by an Int performs integer division: the fractional part is discarded entirely, giving 8, not 8.15. This is different from Python 3, where 163 / 20 always gives a float (8.15) regardless of the types involved, which is exactly why students coming from Python get caught out here. The fix is the one used in the working app above: parse with .toDouble() so at least one operand is a decimal type, and Kotlin's / operator then performs true division. The lesson generalises: in Kotlin, the behaviour of an operator like / depends on the declared types of its operands, not just on the values — always check what type a variable actually is before trusting an arithmetic result.

From Source Code to a Phone in Someone's Hand

The XML and Kotlin files you write are not what runs on a phone. Before installation, Android Studio's build tools compile your Kotlin source into an intermediate bytecode format, then further compile that into DEX bytecode — the format the Android Runtime executes directly. This DEX code is packaged together with your XML layouts, images, and a manifest file (which declares your app's name, permissions, and starting screen) into a single archive. For testing, that archive is an APK (Android Package), which gets installed and run on an emulator — a software-simulated phone running on your computer — or on a real device connected by USB. For public release, Google has for several years required most new apps to be uploaded as an Android App Bundle (.aab) instead of a raw APK; from that bundle, the Play Store generates a smaller, optimised APK tailored to each specific phone's screen size and processor, rather than shipping one bloated file to every device. This is how a single codebase you write on a laptop in your bedroom can end up, after this build pipeline and a Play Store review, running on a phone anywhere among the more than three billion active Android devices Google has reported worldwide — the "billions of users" in this chapter's title are not a slogan, they are the literal install base a working Android app can reach.

The Activity Lifecycle: Why Apps Remember and Forget Things

An Activity is not simply "on" or "off." Android moves it through a defined sequence of states, and each transition calls a specific method you can override — you have already seen one, onCreate(). The full sequence for a screen the user opens, leaves, and returns to is:

  1. onCreate() — called once, when the Activity object is first built; this is where you call setContentView and set up listeners, exactly as in the run rate app.
  2. onStart() — the Activity becomes visible on screen, though not yet interactive.
  3. onResume() — the Activity is now in the foreground and can receive taps; this is the normal "running" state.
  4. onPause() — called the instant the Activity is partially obscured, such as when a dialog pops up or the user starts switching to another app.
  5. onStop() — called once the Activity is fully hidden, for example after the user presses the Home button.
  6. onDestroy() — called when the Activity is finishing for good, or when Android needs to reclaim its memory.

If the user returns from onStop() rather than the Activity being destroyed, Android calls onRestart() then onStart() again, skipping onCreate() — which is exactly why onCreate() is the right place to build the screen once, not the right place to put logic that should re-run every time the user comes back. One consequence surprises almost every beginner: rotating the phone from portrait to landscape, by default, destroys the Activity and creates a brand-new one — onDestroy() then onCreate() again — which is why any values typed into etRuns or etOvers that you stored only in a plain variable would vanish on rotation unless you explicitly save them in the onSaveInstanceState mechanism and read them back from the savedInstanceState: Bundle? parameter that onCreate() already receives — the very parameter visible, unused so far, in the code above.

Check Your Understanding

  1. In the run rate app, which file would you edit to change the button's text to Hindi, and which file would you edit to change what happens when it's tapped? Why does keeping these separate matter for a translator working on the app?
  2. A student changes etOvers's parsing to .toInt() while leaving etRuns as .toDouble(). For runs = 163, overs = 20, what result does the app now show, and why does mixing the two types no longer cause a truncation bug the way using .toInt() for both did?
  3. Put these five events into the correct order: (a) onClickListener block executes; (b) user taps the button; (c) Android delivers a touch event to the Activity; (d) tvResult.text is updated; (e) the screen redraws.
  4. The user rotates their phone while the run rate app is open, right after typing 145 into the runs box but before tapping Calculate. What happens to that typed value by default, and which lifecycle method fires immediately before it is lost?
  5. True or false, with one sentence of justification: "An Android app is just a website opened without an address bar."

Answers: (1) activity_main.xml for the text, MainActivity.kt for the behaviour — a translator can safely edit XML strings without any risk of breaking the tap logic. (2) The result is correctly 8.15; because runs is a Double, Kotlin promotes the whole division to Double arithmetic even though overs is an Int — only Int / Int truncates. (3) b, c, a, d, e. (4) The typed "145" is lost by default because rotation destroys and recreates the Activity; onDestroy() fires right before the old one is thrown away. (5) False — a native Android app is compiled ahead of time and calls Android's APIs directly rather than being rendered live by a browser, which is why it can work offline and access hardware a website cannot.

Summary

An Android app is not one long script but a screen that sits idle until an event — most often a tap — wakes up a specific block of code. Every screen is split into an XML layout, which declares what exists, and a Kotlin Activity, which reacts to what the user does; findViewById is the bridge that lets your code reach into the layout by id. In the run rate app, tapping the button triggers a listener that reads two EditText values as strings, parses them into numbers, divides one by the other, and writes the formatted result into a TextView — and getting that division right depends on knowing that Kotlin's / truncates for whole numbers but not for decimals. Before any of this reaches a phone, your source files are compiled into DEX bytecode and packaged into an APK or App Bundle, which the Play Store can then deliver, in a device-optimised form, to any of the billions of Android devices in use worldwide. And every Activity you build moves through a fixed lifecycle — created, started, resumed, paused, stopped, destroyed — that determines exactly when your setup code runs and when your data quietly disappears unless you deliberately choose to save it.

Practice Exercises

Now it is time to practice! Complete these challenges to solidify your understanding:

  • Exercise 1: Write a short program that demonstrates the core concept from this chapter. Test it with at least 3 different inputs.
  • Exercise 2: Find a real-world example where android development basics: building apps for billions of users is used in an Indian company (like TCS, Infosys, Flipkart, or ISRO). Write a paragraph explaining the connection.
  • Exercise 3: Create a mind-map connecting android development basics: building apps for billions of users to at least 3 other topics you have studied.
← Containers and Docker: Ship Code Like Shipping ContainersHow Blockchain Works: Understanding Distributed Ledger Technology →

Found this useful? Share it!

📱 WhatsApp 🐦 Twitter 💼 LinkedIn