IT272 Mobile Application Development

Mobile Application DevelopmentUnit 317 min read

Activities, Intents, Lifecycle & Task Management in Android

Unit 3 of Mobile Application Development explores Android’s Activity components, Intent mechanisms for navigation, the Activity Lifecycle (onCreate, onStart, onResume, etc.), and Task and Back Stack management. It covers explicit vs. implicit intents, lifecycle callbacks, and how Android manages app states and transiti

TAKEAWAYS:

  • An Activity is a single screen with a UI, managed by the Android system via lifecycle callbacks (e.g., onCreate, onPause).
  • Intents enable communication between Activities (explicit: direct; implicit: system-wide) and can pass data via Intent.putExtra().
  • The Activity Lifecycle determines when an Activity is visible, paused, stopped, or destroyed, affecting resource usage and state retention.
  • Tasks and Back Stack manage navigation history, allowing users to return to previous Activities via the Up button or Back key.
  • Lifecycle-aware components (e.g., ViewModel) help retain data across configuration changes (e.g., screen rotation).
  • Best practices include handling configuration changes properly, avoiding memory leaks, and optimizing intent filters for implicit intents.

Core Concepts: Activities and Their Role

What is an Activity?

An Activity is the entry point for a user interaction in an Android app. It represents a single screen with a UI (e.g., a login screen, a settings menu, or a chat window). Activities are managed by the Activity Manager, which handles their lifecycle and transitions.

Key Characteristics of an Activity:

  • Defined in an AndroidManifest.xml file (e.g., <activity android:name=".MainActivity" />).
  • Extends the android.app.Activity class (or AppCompatActivity for backward compatibility).
  • Can host Fragments, Views, and Adapters (covered in Unit 5).
  • Communicates with other Activities via Intents.

How Activities Work: A Real-World Analogy

Think of an Activity like a waiter in a restaurant:

  • The Activity (waiter) takes your order (onCreate), serves food (onResume), and clears the table (onDestroy) when you leave.
  • If another customer (Activity) interrupts, the waiter pauses your order (onPause) and resumes later (onResume).
  • The Back Stack is like the waiter remembering your table number so you can return after a break.

The Activity Lifecycle: Callbacks and States

The Activity Lifecycle defines 9 callback methods that Android calls to manage an Activity’s state. These callbacks help optimize performance and retain data.

Lifecycle Callbacks and States

stateDiagram-v2
    [*] --> Initialized: onCreate()
    Initialized --> Started: onStart()
    Started --> Resumed: onResume()
    Resumed --> Paused: onPause()
    Paused --> Stopped: onStop()
    Stopped --> Destroyed: onDestroy()
    Paused --> Resumed: onResume()
    Stopped --> Started: onStart()
    Resumed --> Stopped: onStop()
    Stopped --> Paused: onPause()
    Stopped --> Destroyed: onDestroy()

Key States and Callbacks:

State Callback Description Example Trigger
Initialized onCreate() Called once when the Activity is first created. Initialize UI, views, and data here. App launch or startActivity().
Started onStart() Called when the Activity becomes visible (but not interactive). Returning from another Activity.
Resumed onResume() Called when the Activity is in the foreground and interactive. User taps on the Activity.
Paused onPause() Called when another Activity takes focus (e.g., a dialog appears). User opens a popup or switches Activities.
Stopped onStop() Called when the Activity is no longer visible (e.g., user presses Home or switches Apps). User leaves the Activity.
Destroyed onDestroy() Called before the Activity is destroyed (e.g., system kills it for memory). Low memory or explicit finish().

Worked Example: Lifecycle in a Chat App

Scenario: A user opens a WhatsApp chat (Activity A), then opens a media picker (Activity B). Activity A is paused but not destroyed.

Step-by-Step Trace:

  1. Activity A (onCreate):

    • User opens the chat app.
    • onCreate() initializes the chat UI and loads messages.
    • State: Resumed.
  2. Activity B (onStart, onResume):

    • User taps to send an image.
    • onPause() is called on Activity A (UI is still visible but not interactive).
    • Activity B starts: onCreate() → onStart() → onResume().
    • State: Activity A = Paused; Activity B = Resumed.
  3. Return to Activity A (onResume):

    • User selects an image and returns to the chat.
    • onPause() is called on Activity B.
    • onResume() is called on Activity A (UI becomes interactive again).
    • State: Activity A = Resumed; Activity B = Stopped.
  4. App Switch (onStop, onDestroy):

    • User presses the Home button.
    • onPause() → onStop() on Activity A (no longer visible).
    • If the system kills Activity A for memory, onDestroy() is called.

Why This Matters:

  • Data Loss Prevention: Save critical data in onPause() or onSaveInstanceState().
  • Performance: Release resources (e.g., cameras, sensors) in onStop().
  • User Experience: Avoid blocking the UI in onResume() (use background threads).

Intents: Communication Between Activities

What is an Intent?

An Intent is a messenger object that requests an action (e.g., open a camera, share text, or launch an Activity). It can be:

  • Explicit: Targets a specific Activity (e.g., MainActivity).
  • Implicit: Declares a general action (e.g., "open a browser") and lets the system choose the best app.

Types of Intents

Type Use Case Example
Explicit Directly specifies the target Activity using its class name. Intent intent = new Intent(this, SettingsActivity.class);
Implicit Specifies an action (e.g., ACTION_VIEW, ACTION_SEND) and data type. Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("text/plain");
Broadcast Sends a system-wide message (e.g., battery low, network change). Intent intent = new Intent("com.example.BATTERY_LOW");
Service Starts a background Service (covered in Unit 9). Intent intent = new Intent(this, MyService.class);

How Intents Work: Step-by-Step

sequenceDiagram
    participant User
    participant ActivityA
    participant AndroidSystem
    participant ActivityB

    User->>ActivityA: Clicks "Share" button
    ActivityA->>AndroidSystem: Creates Intent (ACTION_SEND, text/plain)
    AndroidSystem->>ActivityB: Delivers Intent to WhatsApp/Khalti
    ActivityB->>AndroidSystem: Returns RESULT_OK or RESULT_CANCELED
    AndroidSystem-->>ActivityA: Notifies result

Worked Example: Sharing Text via Intent (Khalti App)

Scenario: A user in the Khalti app wants to share a payment link.

Code Example:

// In ActivityA (e.g., PaymentSuccessActivity)
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, "Pay via Khalti: https://khalti.com/pay/12345");
startActivity(Intent.createChooser(shareIntent, "Share via"));

Step-by-Step Execution:

  1. Intent Creation:

    • ACTION_SEND tells Android: "I want to share something."
    • setType("text/plain") specifies the data format (text).
    • putExtra() adds the payment link.
  2. System Chooser:

    • Android displays a list of apps (WhatsApp, Email, Messenger) that can handle ACTION_SEND.
    • User selects WhatsApp.
  3. Activity B (WhatsApp) Receives Intent:

    • WhatsApp’s onCreate() receives the Intent via getIntent().
    • It extracts the text using getStringExtra(Intent.EXTRA_TEXT).
  4. Result Handling (Optional):

    • If Activity B (WhatsApp) needs to confirm sharing, it calls:
      setResult(RESULT_OK, new Intent());
      finish();
      
    • Activity A can check the result with startActivityForResult().

Real-World Tie-In:

  • Khalti uses implicit intents to let users share payment links via any messaging app.
  • Pathao uses explicit intents to open its driver app when a user requests a ride.
  • Daraz uses intents to launch product details or the cart screen.

Task and Back Stack: Managing Navigation

What is a Task?

A Task is a collection of Activities grouped by the system (e.g., all Activities launched by a single user action). The Back Stack is a LIFO (Last-In-First-Out) stack that tracks the order of Activities in a Task.

Example Task Flow:

  1. User opens Daraz (Activity A: Home Screen).
  2. User taps a product → Product Details (Activity B).
  3. User adds to cart → Cart Screen (Activity C).
  4. User presses Back:
    • Activity C is removed from the stack.
    • Activity B becomes visible again.

How the Back Stack Works

flowchart LR
    A["Daraz Home\n(Activity A)"] --> B["Product Details\n(Activity B)"]
    B --> C["Cart Screen\n(Activity C)"]
    C -->|"Back Press"| B
    B -->|"Back Press"| A
    A -->|"Home Button"| [*]

Key Points:

  • The Up button (or Back key) navigates the Back Stack.
  • Pressing Home or Recents removes the Task from memory (unless it’s a persistent Task).
  • SingleTop and SingleTask launch modes affect how Activities are added to the stack.

Worked Example: Ncell’s App Navigation

Scenario: A user checks Ncell’s balance via the app.

  1. Launch Ncell App (Activity A: Home Screen)

    • Task Stack: [A]
  2. Tap "Check Balance" (Activity B: Balance Screen)

    • Task Stack: [A, B]
  3. Tap "Back"

    • Activity B is finished; Task Stack: [A]
  4. Press Home → Reopen Ncell

    • Android restores the Task Stack: [A, B] (if not cleared by the system).

Problem: If the user rotates the screen, Android recreates Activities but retains the Task Stack. Solution: Use android:configChanges in AndroidManifest.xml or override onSaveInstanceState().


Lifecycle-Aware Components: ViewModel and LiveData

Why Use Lifecycle-Aware Components?

Activities can be destroyed and recreated (e.g., screen rotation). To retain data:

  • Use ViewModel (scoped to an Activity/Fragment).
  • Use LiveData (observes lifecycle changes).

Example: Retaining Data in a Bank App

Scenario: A user enters a Nabil Bank loan amount but rotates the screen.

Without ViewModel:

  • onDestroy() is called → all data in onCreate() is lost.

With ViewModel:

// In MainActivity
public class LoanActivity extends AppCompatActivity {
    private LoanViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewModel = new ViewModelProvider(this).get(LoanViewModel.class);

        // Observe LiveData
        viewModel.getLoanAmount().observe(this, amount -> {
            editTextAmount.setText(String.valueOf(amount));
        });
    }

    public void submitLoan(View view) {
        String amount = editTextAmount.getText().toString();
        viewModel.setLoanAmount(Double.parseDouble(amount));
    }
}

// ViewModel class
public class LoanViewModel extends ViewModel {
    private MutableLiveData<Double> loanAmount = new MutableLiveData<>();

    public LiveData<Double> getLoanAmount() {
        return loanAmount;
    }

    public void setLoanAmount(Double amount) {
        loanAmount.setValue(amount);
    }
}

How It Works:

  1. User enters 50000 in editTextAmount and rotates the screen.
  2. onDestroy() is called on LoanActivity, but ViewModel survives.
  3. onCreate() recreates the Activity and restores the loanAmount via LiveData.

Common Pitfalls and Best Practices

1. Memory Leaks

Problem: Holding a reference to an Activity in a static variable or non-lifecycle-aware component. Solution: Use ViewModel or LifecycleObserver.

2. Improper Configuration Changes

Problem: Activities restart on screen rotation, losing UI state. Solution:

  • Save state in onSaveInstanceState().
  • Use ViewModel for data.
  • Add android:configChanges="orientation|screenSize" (but handle changes manually).

3. Inefficient Intent Filters

Problem: Overly broad implicit intents (e.g., android.intent.action.VIEW without constraints). Solution: Narrow intent filters with setDataAndType() or categories.

4. Blocking the UI Thread

Problem: Long-running tasks (e.g., network calls) in onResume(). Solution: Use AsyncTask, Coroutines, or RxJava.


In the Real World

1. eSewa: Payment Flow with Intents

  • Idea Used: Explicit Intents for internal navigation.
  • How: When a user selects "Pay Bill," eSewa launches the PaymentActivity via:
    Intent intent = new Intent(eSewa.this, PaymentActivity.class);
    intent.putExtra("BILL_ID", billId);
    startActivity(intent);
    
  • Why: Ensures only eSewa’s PaymentActivity handles the intent, avoiding ambiguity.

2. Pathao: Ride Request with Implicit Intents

  • Idea Used: Implicit Intents for third-party integrations.
  • How: Pathao uses ACTION_VIEW to open Google Maps for navigation:
    Intent intent = new Intent(Intent.ACTION_VIEW,
        Uri.parse("https://maps.google.com/?saddr=" + currentLocation + "&daddr=" + destination));
    startActivity(intent);
    
  • Why: Lets users choose their preferred maps app (Google Maps, Maps.me).

3. NTC’s App: Task Management for Ticket Booking

  • Idea Used: Back Stack for seamless navigation.
  • How: When a user books a bus ticket:
    1. HomeActivity → SearchActivity → BookingActivity → ConfirmationActivity.
    2. Pressing Back returns to BookingActivity, then SearchActivity.
  • Why: Provides a consistent user experience without losing context.

4. NEPSE App: LiveData for Stock Prices

  • Idea Used: Lifecycle-aware LiveData to update UI dynamically.
  • How: Stock prices update in real-time without recreating Activities on rotation.
  • Code Snippet:
    LiveData<String> stockPrice = viewModel.getStockPrice();
    stockPrice.observe(this, price -> {
        textViewPrice.setText(price);
    });
    

Exam Tip

What to Expect in TU/PU Exams

  1. Short Questions (2-5 marks):

    • Define Activity, Intent, or Back Stack.
    • Differentiate between explicit and implicit intents.
    • List 3 lifecycle callbacks and their order.
  2. Programming Questions (10-15 marks):

    • Write code to:
      • Launch an Activity with an Intent.
      • Pass data between Activities using putExtra() and getIntent().
      • Handle configuration changes with onSaveInstanceState().
    • Debug a memory leak in an Activity.
  3. Scenario-Based Questions (10-20 marks):

    • Explain how WhatsApp uses Intents to share media.
    • Describe the lifecycle of a Daraz product details screen when the user rotates the device.
    • Design a Task Stack for a banking app with 3 Activities.
  4. Diagram Questions (5-10 marks):

    • Draw the Activity Lifecycle diagram and label all callbacks.
    • Sketch the Back Stack for a given sequence of Activities (e.g., Home → Settings → Profile).

How to Score Full Marks

  • For Theory: Use bullet points and tables to organize answers (examiners love clarity).
  • For Code: Always include:
    1. The Intent creation (explicit/implicit).
    2. Data passing (putExtra()).
    3. Result handling (startActivityForResult() if needed).
  • For Diagrams: Label every state and transition (e.g., "onPause() → onStop()").
  • For Scenarios: Tie answers to real apps (e.g., "Like Khalti, the app should use ViewModel to retain payment data").

Common Mistakes to Avoid

  • Forgetting super.onCreate(savedInstanceState) in onCreate().
  • Not handling configuration changes (e.g., ignoring onSaveInstanceState()).
  • Using static variables to store Activity references (causes leaks).
  • Overcomplicating intent filters (stick to necessary actions/categories).

Final Checklist Before the Exam

Topic Key Points to Remember
Activity Lifecycle Order of callbacks: onCreate() → onStart() → onResume() → onPause() → onStop().
Intents Explicit: new Intent(this, TargetActivity.class). Implicit: ACTION_SEND, setType().
Back Stack LIFO order; use finish() to remove Activities.
ViewModel Retains data across configuration changes.
Best Practices Avoid memory leaks; use LiveData for UI updates.

Based on the TU BIM syllabus for Mobile Application Development (IT272), unit 3.

Discussion

Loading…