Install Android Studio and Create the First Compose App
Module: Foundations and Tooling · Lecture 2 of 33
Build a reproducible Android development environment and run the same application on an emulator and a physical device. This lecture moves from the mental model to implementation, diagnosis, testing, and production tradeoffs.
Prerequisites and Learning Outcomes
Complete the previous lecture and retain its working project. By the end, you should be able to explain the responsibility, implement the example, force a realistic failure, and defend where the behavior belongs in the architecture.
- Explain the concept without relying on framework buzzwords.
- Implement it with idiomatic, null-safe Kotlin.
- Verify success, empty, loading, cancellation, and failure states when applicable.
- Write a focused automated test and identify one production risk.
Conceptual Model
1. Android Studio manages the SDK, emulator, profilers, Gradle integration, and Compose previews.
This principle changes an implementation decision, not only vocabulary. Identify the owner, input, output, lifetime, and failure behavior before adding framework code. Then isolate the rule behind a small typed boundary so it can be tested without launching the complete application.
To prove understanding, create one valid example and one counterexample. Predict the result, run the analyzer or test, and explain why the observed behavior follows from the Android or Kotlin model described above.
2. SDK versions have different meanings: compileSdk exposes APIs, minSdk sets device eligibility, and targetSdk opts into platform behavior.
This principle changes an implementation decision, not only vocabulary. Identify the owner, input, output, lifetime, and failure behavior before adding framework code. Then isolate the rule behind a small typed boundary so it can be tested without launching the complete application.
To prove understanding, create one valid example and one counterexample. Predict the result, run the analyzer or test, and explain why the observed behavior follows from the Android or Kotlin model described above.
3. A clean first build proves that JDK, Gradle, SDK, emulator, and application configuration agree.
This principle changes an implementation decision, not only vocabulary. Identify the owner, input, output, lifetime, and failure behavior before adding framework code. Then isolate the rule behind a small typed boundary so it can be tested without launching the complete application.
To prove understanding, create one valid example and one counterexample. Predict the result, run the analyzer or test, and explain why the observed behavior follows from the Android or Kotlin model described above.
Mental-model exercise
Draw the runtime path for this feature as boxes and arrows. Include the user or operating-system event, composable, state owner, ViewModel when appropriate, repository, data source, and final rendered state. Mark which arrows are synchronous, suspending, streamed, or external to the process. Next, mark every place that can fail or be canceled. This diagram should make duplicate ownership, hidden dependencies, and missing recovery paths visible before the implementation becomes large.
Worked Kotlin Example
Type this example into the course project. Read the public contract first, trace one input through every line, and identify what owns any state or resource.
./gradlew tasks
./gradlew lint testDebugUnitTest
./gradlew assembleDebug
adb devices
Walkthrough
- Locate the inputs and their nullability or validity constraints.
- Trace the successful path and write down the value and type of each important expression.
- Change one assumption: use absent, malformed, delayed, denied, very large, or stale data as appropriate.
- Check lifecycle and cancellation behavior by leaving and returning to the screen.
- Extract business or data policy from UI code and protect it with a unit test.
Guided Lab
Commit after each verified step. The commit history should tell the story of the feature and make failed experiments recoverable.
Step 1: Install the stable IDE and required SDK tools.
Implement this in a dedicated branch. Keep the change narrow, run the relevant Gradle task, and inspect the behavior on a representative emulator or device. Record the expected result before execution and retain a focused test or repeatable verification command.
Step 2: Create an Empty Activity Compose project with a reverse-domain application ID.
Implement this in a dedicated branch. Keep the change narrow, run the relevant Gradle task, and inspect the behavior on a representative emulator or device. Record the expected result before execution and retain a focused test or repeatable verification command.
Step 3: Run on an emulator, enable developer options on a device, and run there too.
Implement this in a dedicated branch. Keep the change narrow, run the relevant Gradle task, and inspect the behavior on a representative emulator or device. Record the expected result before execution and retain a focused test or repeatable verification command.
Step 4: Commit the Gradle wrapper and version catalog.
Implement this in a dedicated branch. Keep the change narrow, run the relevant Gradle task, and inspect the behavior on a representative emulator or device. Record the expected result before execution and retain a focused test or repeatable verification command.
Debugging Workshop
Advanced Android work depends on explaining failures across the OS, lifecycle, coroutine, data, and rendering boundaries. Practice with the following cases.
Failure 1
Using a machine-specific absolute SDK path in source control.
Reproduce the symptom with fixed input. Reduce it to the smallest component or layer, inspect lifecycle and ownership, correct the underlying contract, and add a regression test. Avoid hiding the failure with a delay, null assertion, broad catch, or UI-only workaround.
Failure 2
Ignoring Gradle or doctor-style warnings until release day.
Reproduce the symptom with fixed input. Reduce it to the smallest component or layer, inspect lifecycle and ownership, correct the underlying contract, and add a regression test. Avoid hiding the failure with a delay, null assertion, broad catch, or UI-only workaround.
Architecture and Production Decisions
- Ownership: state and resources need one clear owner and matching cleanup lifetime.
- Dependency direction: composables render and emit events; ViewModels coordinate screen behavior; repositories own application data; data sources own transport or persistence details.
- Reliability: distinguish retryable failures from authentication, validation, conflict, and permanent failures.
- Accessibility: verify semantics, focus, touch target size, font scaling, contrast, and non-visual state feedback.
- Performance: measure release-like behavior with traces or benchmarks before optimizing.
- Security: validate external input, minimize stored data, authorize on the server, and keep privileged secrets out of the application.
Independent Assignment
Build: Install the stable IDE and required SDK tools. Create an Empty Activity Compose project with a reverse-domain application ID. Run on an emulator, enable developer options on a device, and run there too. Commit the Gradle wrapper and version catalog.
Add a realistic failure and recovery path that the worked example does not already show. Submit source, analyzer and test output, one screenshot or trace where useful, and a short architecture note explaining ownership and tradeoffs.
Knowledge Check
- What problem does this concept solve?
- Which layer owns it, and which layer must not own it?
- What happens during configuration change, backgrounding, cancellation, or process death?
- Which malformed or adversarial input should be tested?
- What evidence would demonstrate production readiness?
Answer guide
A complete answer must use these facts: Android Studio manages the SDK, emulator, profilers, Gradle integration, and Compose previews. SDK versions have different meanings: compileSdk exposes APIs, minSdk sets device eligibility, and targetSdk opts into platform behavior. A clean first build proves that JDK, Gradle, SDK, emulator, and application configuration agree.
It should name an observable behavior, a failure state, and a test boundary. Performance claims need measurement; security claims need a server-side trust boundary; accessibility claims need semantics and device-level verification.
Summary and Official Reference
Android Studio manages the SDK, emulator, profilers, Gradle integration, and Compose previews. SDK versions have different meanings: compileSdk exposes APIs, minSdk sets device eligibility, and targetSdk opts into platform behavior. A clean first build proves that JDK, Gradle, SDK, emulator, and application configuration agree.
Compare your work with the official Android documentation for this topic. You are ready to continue when you can rebuild the central example, explain its lifecycle and ownership, and show a passing regression test.
Complete Android curriculum · Previous: How Modern Android Apps Work · Next: Kotlin Essentials for Android Developers
