Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Android Activity Stacks, Process Lifecycles, and Inter-Process Data Transfer

Tech 1

Task Management and Navigation Stacks

When users interact with an application, they engage with a sequence of screens represented by Activity instances. The system organizes these instances into a task—a cohesive unit that arranges activities in a last-in-first-out (LIFO) structure known as the back stack. Consider an email client: selecting a message pushes a detail view onto the stack, while pressing the back button pops that view and restores the previous list state.

Launching an activity places it at the top of the stack and shifts focus to it, pausing the previous activity but preserving its UI state. Android 7.0+ introduces multi-window support where each window maintains independent task stacks. On desktop environments like Chrome OS, the system manages task groups per window.

Tasks typically originate from the home screen launcher. Tapping an icon brings the associated task to the foreground or creates a new task with the root activity if none exists. When multiple applications run simultaneously, background tasks retain their stack states but lose focus, enabling multitasking scenarios where users switch between distinct application contexts.

Activity Launch Behaviors

The system provides several mechanisms to control how activities instantiate and associate with tasks:

Manifest Declarations

The launchMode attribute determines instantiation behavior:

  • standard: Default behavior creating new instances per launch request. Multiple instences can exist across different tasks.
  • singleTop: Reuses the existing top-of-stack instance via onNewIntent() when available, otherwise creates new.
  • singleTask: Maintains a single instance across the entire system. If the instance exists in another task, that task surfaces to foreground.
  • singleInstance: Similar to singleTask but prohibits additional activities from joining its task.

Intent Modifiers

Runtime flags override manifest configurations:

  • FLAG_ACTIVITY_NEW_TASK: Mirrors singleTask behavior, initiating new tasks or surfacing existing ones.
  • FLAG_ACTIVITY_SINGLE_TOP: Mirrors singleTop behavior.
  • FLAG_ACTIVITY_CLEAR_TOP: Destroys all activities above the target instance, delivering the intent to the resumed target.

Task Affinity and Stack Management

Task affinity defines which task an activity prefers to join. By default, activities within an application share the same affinity. The taskAffinity attribute modifies this association, useful when combining activities from different applications or separating logical modules within one APK.

When allowTaskReparenting is enabled, activities migrate to tasks matching their affinity when those tasks enter the foreground. This proves valuable for reusable components like weather widgets that should appear within their parent application's task rather than the launching app's context.

For stack maintenance, several attribute control persistence:

  • alwaysRetainTaskState: Prevents automatic clearing of background task stacks.
  • clearTaskOnLaunch: Resets the stack to root upon re-entry.
  • finishOnTaskLaunch: Removes specific activities when users return to tasks.

Application Process Lifecycle

Android applications execute within Linux processes whose lifespans depend on system resource availability and component states. The framework categorizes processes into a hierarchy of importance:

  1. Foreground Processes: Currently executing user-visible operations—running activities in resumed state, active broadcast receivers, or service lifecycle callbacks. These survive until memory exhaustion.

  2. Visible Processes: Hosting paused activities (visible behind dialogs) or foreground services. These terminate only when necessary to sustain foreground processes.

  3. Service Processes: Running services initiated via startService(), performing background operations like synchronization. Extended execution (30+ minutes) may downgrade priority to cached status.

  4. Cached Processes: Inactive activities in stopped states, maintained for quick relaunch but terminated first during memory pressure. The system maintains these in a least-recently-used queue.

Process importance elevates when bound to higher-priority components through Context.BIND_AUTO_CREATE or ContentProvider dependencies.

Inter-Process Communication and Data Transfer

For passing information between components, Android utilizes Bundle objects optimized for parceling. When launching activities:

val navigationIntent = Intent(applicationContext, DetailView::class.java).apply {
    putExtra("item_identifier", "xyz789")
    putExtra("content_type", "article")
}
startActivity(navigationIntent)

For complex objects requiring custom serialization, implement Parcelable:

class MediaMetadata(val id: String, val duration: Long) : Parcelable {
    constructor(parcel: Parcel) : this(
        parcel.readString() ?: "",
        parcel.readLong()
    )

    override fun writeToParcel(dest: Parcel, flags: Int) {
        dest.writeString(id)
        dest.writeLong(duration)
    }

    override fun describeContents(): Int = 0

    companion object {
        @JvmField
        val CREATOR: Parcelable.Creator<MediaMetadata> = object : Parcelable.Creator<MediaMetadata> {
            override fun createFromParcel(source: Parcel): MediaMetadata = MediaMetadata(source)
            override fun newArray(size: Int): Array<MediaMetadata?> = arrayOfNulls(size)
        }
    }
}

Critical Constraints

Binder transactions impose a 1MB buffer limit shared across all application processes. Exceeding this threshold triggers TransactionTooLargeException. This constraint affects onSaveInstanceState(), activity launches, and system interactions.

Guidelines for data transfer:

  • Keep intent extras under 100KB
  • Maintain saved state below 50KB
  • Avoid custom Parcelable objects when broadcasting to system components (alarms, notifications), as the framework may strip unrecognized classes during intent modification
  • Never persist Parcel data to disk or networks

Android 7.0+ throws runtime exceptions for size violations, while earlier versions log warnings silently.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.