Skip to content

TD6 — Android Studio & NotesPad v1

← Part 3 Overview

S7 Inf A3 — Java for Graphical and Mobile Programming
Stéphane Derrode — Centrale Lyon
Part 3 — Android
Duration: 2h · Follow the setup tutorial before starting


Objectives

  • Install Android Studio and configure an emulator
  • Understand the project structure generated by Android Studio
  • Build NotesPad v1: one Activity, one layout, one button
  • Handle a click event and display a Toast
  • Use Logcat to debug

Part 0 — Environment Setup (done before the session)

Follow the Android Studio & Emulator Setup Tutorial available on the course website before arriving.

Quick check — Android Studio opens and the emulator starts:

  1. Open Android Studio
  2. Open AVD Manager (Tools → Device Manager)
  3. Start the Pixel 6a API 33 emulator
  4. Verify the emulator boots to the Android home screen

If anything fails, come 10 minutes early.


Part 1 — Create the NotesPad Project (15 min)

1.1 New project

In Android Studio:

  1. File → New → New Project
  2. Choose template: Empty Views Activity
  3. Fill in:
  4. Name: NotesPad
  5. Package name: com.s7infa3.notespad
  6. Save location: your choice
  7. Language: Java
  8. Minimum SDK: API 26 (Android 8.0)
  9. Click Finish and wait for Gradle sync

1.2 Explore the generated structure

Locate and open each file. Note what it contains.

File Location Purpose
MainActivity.java app/src/main/java/com/s7infa3/notespad/ Activity logic
activity_main.xml app/src/main/res/layout/ UI definition
strings.xml app/src/main/res/values/ Text constants
AndroidManifest.xml app/src/main/ App declaration
build.gradle (app) app/ Dependencies

1.3 Run the default app

Click ▶ Run (Shift+F10). The emulator should show "Hello World!".


Part 2 — Build the Layout (25 min)

Replace the content of activity_main.xml with the following:

<?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">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/app_name"
        android:textSize="28sp"
        android:textStyle="bold"
        android:layout_marginBottom="24dp"/>

    <EditText
        android:id="@+id/noteInput"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/hint_note"
        android:inputType="text"
        android:layout_marginBottom="12dp"/>

    <Button
        android:id="@+id/addButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/btn_add"/>

    <TextView
        android:id="@+id/statusView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text=""
        android:textSize="14sp"
        android:layout_marginTop="16dp"
        android:textColor="#757575"/>

</LinearLayout>

Now open strings.xml and add the missing strings:

<resources>
    <string name="app_name">NotesPad</string>
    <string name="hint_note">Enter a note…</string>
    <string name="btn_add">Add</string>
    <string name="error_empty">Note cannot be empty</string>
    <string name="note_added">Note added!</string>
</resources>

Run the app — you should see the layout. The button does nothing yet.


Part 3 — Add the Click Handler (30 min)

3.1 Connect the widgets

Replace the content of MainActivity.java:

package com.s7infa3.notespad;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "NotesPad";

    private List<String> notes = new ArrayList<>();
    private EditText noteInput;
    private TextView statusView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 1. Get widget references
        noteInput  = findViewById(R.id.noteInput);
        statusView = findViewById(R.id.statusView);
        Button addButton = findViewById(R.id.addButton);

        // 2. Set up the click listener
        addButton.setOnClickListener(v -> addNote());
    }

    private void addNote() {
        String text = noteInput.getText().toString().trim();

        if (text.isEmpty()) {
            Toast.makeText(this,
                R.string.error_empty,
                Toast.LENGTH_SHORT).show();
            return;
        }

        notes.add(text);
        noteInput.setText("");
        statusView.setText(notes.size() + " note(s) in memory");
        Log.d(TAG, "Note added: " + text
            + " — total: " + notes.size());

        Toast.makeText(this,
            R.string.note_added,
            Toast.LENGTH_SHORT).show();
    }
}

3.2 Test

  1. Run the app
  2. Type a note and tap Add → Toast appears, status updates
  3. Tap Add with an empty field → error Toast appears
  4. Add 3 notes → status shows "3 note(s) in memory"
  5. Open Logcat (bottom panel in Android Studio), filter by NotesPad → see your Log.d() messages

Part 4 — Explore the Lifecycle (20 min)

4.1 Override lifecycle methods

Add the following methods to MainActivity.java to observe the lifecycle:

@Override
protected void onStart() {
    super.onStart();
    Log.d(TAG, "onStart()");
}

@Override
protected void onResume() {
    super.onResume();
    Log.d(TAG, "onResume()");
}

@Override
protected void onPause() {
    super.onPause();
    Log.d(TAG, "onPause() — notes in memory: "
        + notes.size());
}

@Override
protected void onStop() {
    super.onStop();
    Log.d(TAG, "onStop()");
}

@Override
protected void onDestroy() {
    super.onDestroy();
    Log.d(TAG, "onDestroy()");
}

4.2 Observe the sequence

With Logcat open and filtered by NotesPad:

  1. Launch the app → which methods are called?
  2. Press Home (not Back) → which methods are called?
  3. Reopen the app → which methods are called?
  4. Press Back → which methods are called?
  5. Add notes then rotate the emulator (Ctrl+Left/Right in emulator) → what happens to your notes?

The notes disappear on rotation — this is the problem that onSaveInstanceState() and SharedPreferences solve (CM8).


Part 5 — Exploration (remaining time)

5.1 Change the button color: in activity_main.xml, add android:backgroundTint="@color/purple_500". Where does purple_500 come from? Open colors.xml.

5.2 Add a second button Clear All that empties the notes list and resets the status text.

5.3 Make the Add button disabled at startup and enable it only when the EditText is not empty. Use a TextWatcher:

noteInput.addTextChangedListener(new TextWatcher() {
    @Override public void beforeTextChanged(
        CharSequence s, int start, int count, int after) {}
    @Override public void onTextChanged(
        CharSequence s, int start, int before, int count) {
        addButton.setEnabled(s.toString().trim().length() > 0);
    }
    @Override public void afterTextChanged(Editable s) {}
});

Deliverable

No formal submission. Verify that: - The app runs on the emulator - Adding a note shows a Toast and updates the status - Empty note shows an error Toast - Lifecycle methods print to Logcat correctly

Keep this project — you will extend it in TD7.


Common Errors

Error Cause Fix
Gradle sync failed Missing SDK Open SDK Manager (Tools → SDK Manager), install API 33
Cannot resolve symbol R XML has an error Fix the XML error; rebuild (Build → Rebuild Project)
NullPointerException on findViewById Called before setContentView() Always call setContentView() first in onCreate()
Toast shows nothing Forgot .show() Add .show() at the end of the Toast chain
Emulator is very slow Hardware acceleration off Enable HAXM or use an x86 system image