Android Fundamentals with Java

Project: A Two-Screen Android App

18 min Lesson 10 of 12

Project: A Two-Screen Android App

Everything you have learned in this tutorial — Activities, layouts, the lifecycle, the Manifest, resources, Intents, and logging — converges in this final lesson. You will build a complete, working Android app that has two screens: a Home screen where the user types their name, and a Greeting screen that displays a personalised welcome message. The navigation between them uses an explicit Intent carrying an Extra, exactly as a professional Android developer would write it.

What you will practise: creating a second Activity class and layout, declaring it in the Manifest, launching it with startActivity(), passing data via Intent extras, reading that data in the receiving Activity, and wiring up a back-navigation button — all in Java.

App Architecture at a Glance

The app has exactly two screens:

  • MainActivity — a text field (EditText) and a "Say Hello" button (Button).
  • GreetingActivity — a TextView showing "Hello, name!" and a "Go Back" button.

Data flows in one direction: MainActivity reads the name from the EditText, bundles it into an Intent extra, and starts GreetingActivity. The greeting screen unpacks the extra and renders it. No database, no network — clean and focused on navigation.

Step 1 — The Main Layout (activity_main.xml)

Open res/layout/activity_main.xml and replace its content with a simple vertical LinearLayout:

<?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:gravity="center" android:padding="32dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/prompt_name" android:textSize="18sp" android:layout_marginBottom="16dp" /> <EditText android:id="@+id/etName" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/hint_name" android:inputType="textPersonName" android:layout_marginBottom="24dp" /> <Button android:id="@+id/btnSayHello" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/btn_say_hello" /> </LinearLayout>

Step 2 — The Greeting Layout (activity_greeting.xml)

Create a new layout file: right-click res/layout → New → Layout Resource File → name it activity_greeting. Use this content:

<?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:gravity="center" android:padding="32dp"> <TextView android:id="@+id/tvGreeting" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="24sp" android:textStyle="bold" android:layout_marginBottom="32dp" /> <Button android:id="@+id/btnGoBack" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/btn_go_back" /> </LinearLayout>

Step 3 — String Resources (res/values/strings.xml)

All user-visible text lives in strings.xml — never hardcode strings in layouts or Java code:

<resources> <string name="app_name">TwoScreenApp</string> <string name="prompt_name">Enter your name:</string> <string name="hint_name">Your name</string> <string name="btn_say_hello">Say Hello</string> <string name="btn_go_back">Go Back</string> <string name="greeting_format">Hello, %1$s!</string> </resources>

The %1$s placeholder is used with getString(R.string.greeting_format, name) in Java to produce the formatted greeting.

Step 4 — MainActivity.java

This Activity reads the name and fires the Intent:

package com.example.twoscreenapp; import android.content.Intent; import android.os.Bundle; import android.text.TextUtils; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { // Key constant for the Intent extra — define it here so both // activities agree on the same string without duplication public static final String EXTRA_NAME = "com.example.twoscreenapp.EXTRA_NAME"; private EditText etName; private Button btnSayHello; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); etName = findViewById(R.id.etName); btnSayHello = findViewById(R.id.btnSayHello); btnSayHello.setOnClickListener(v -> launchGreeting()); } private void launchGreeting() { String name = etName.getText().toString().trim(); if (TextUtils.isEmpty(name)) { Toast.makeText(this, "Please enter your name", Toast.LENGTH_SHORT).show(); return; } // Build an explicit Intent targeting GreetingActivity Intent intent = new Intent(this, GreetingActivity.class); intent.putExtra(EXTRA_NAME, name); // attach the name as an extra startActivity(intent); // launch the second screen } }
Define extra keys as public static final String constants on the sending Activity. The receiving Activity references them as MainActivity.EXTRA_NAME instead of typing a raw string — a typo in a raw string silently returns null, whereas a compile error on a constant is caught immediately.

Step 5 — GreetingActivity.java

Create the second Activity: right-click the package → New → Java Class → name it GreetingActivity. Extend AppCompatActivity:

package com.example.twoscreenapp; import android.os.Bundle; import android.widget.Button; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; public class GreetingActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_greeting); // Retrieve the name that MainActivity put into the Intent String name = getIntent().getStringExtra(MainActivity.EXTRA_NAME); // Format and display the greeting TextView tvGreeting = findViewById(R.id.tvGreeting); tvGreeting.setText(getString(R.string.greeting_format, name)); // "Go Back" finishes this Activity, revealing MainActivity underneath Button btnGoBack = findViewById(R.id.btnGoBack); btnGoBack.setOnClickListener(v -> finish()); } }

Calling finish() destroys GreetingActivity and pops it from the back stack, returning the user to MainActivity — exactly what the system Back button does. You do not start a new instance of MainActivity; that would create a duplicate and break the back stack.

Never call startActivity(new Intent(this, MainActivity.class)) from a back button. This pushes a fresh MainActivity onto the stack instead of returning to the existing one. Always use finish() to go back one level.

Step 6 — Registering GreetingActivity in the Manifest

Every Activity must be declared in AndroidManifest.xml. Android Studio's wizard adds it automatically when you use New → Activity, but if you created the class manually you must add it yourself:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.twoscreenapp"> <application android:allowBackup="true" android:label="@string/app_name" android:theme="@style/Theme.TwoScreenApp"> <!-- Entry-point Activity --> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <!-- Second screen — no intent-filter needed; launched explicitly --> <activity android:name=".GreetingActivity" android:exported="false" android:parentActivityName=".MainActivity" /> </application> </manifest>

The android:parentActivityName attribute tells the system and the action bar's Up (←) button that MainActivity is the logical parent. It is good practice even though our explicit "Go Back" button already handles navigation.

Step 7 — Run and Verify

Launch the app on the emulator or a device. The expected behaviour is:

  1. The home screen appears with an EditText and a "Say Hello" button.
  2. Leaving the field empty and tapping the button shows a Toast — no navigation occurs.
  3. Typing a name and tapping "Say Hello" navigates to the greeting screen showing "Hello, name!".
  4. Tapping "Go Back" or the system Back button returns to the home screen.
  5. The name field retains its value because MainActivity was never destroyed — it is merely paused and stopped while GreetingActivity is visible.

Lifecycle Review

When the user navigates forward: MainActivity.onPause()MainActivity.onStop()GreetingActivity.onCreate()GreetingActivity.onStart()GreetingActivity.onResume(). When they return: GreetingActivity.onPause()GreetingActivity.onStop()GreetingActivity.onDestroy()MainActivity.onRestart()MainActivity.onStart()MainActivity.onResume(). MainActivity is never fully destroyed; it resumes with its view state intact.

Summary

You have built a complete two-screen Android app in Java. The key patterns to carry forward are: declare every Activity in the Manifest, use explicit Intents with typed extra-key constants to pass data, call finish() (not a new Intent) to go back, and keep all user-facing strings in strings.xml. These fundamentals scale directly to apps with ten or twenty screens — the mechanics are identical regardless of complexity.