In 2018, Google popularized Single Activity Architecture as the modern way to build Android apps. Like many other teams, we adopted it across our entire codebase.

Eight years later, after running large-scale production apps, we partially reversed that decision.

This article explains why single-activity architecture broke down for us at scale, where multiple activities still make sense, and how a hybrid approach helped us regain stability, modularity, and development velocity.

This isn’t about contradicting Google’s recommendations—it’s about adapting them to the realities of production at scale. Over 12 years of shipping Android apps, I’ve learned that architectural choices age. Patterns that simplify a greenfield app can quietly turn into constraints as the product and organization grow.

Who this article is for: Senior Android engineers, tech leads, and teams maintaining large production apps — not greenfield tutorials or MVPs.

Part 1: Why Single Activity Felt Like the Right Choice

Before we critique it, let's acknowledge why single activity architecture deserved its moment.

Issues We Inherited from the Legacy App

Before adopting a single activity, our app looked something like this:

LoginActivity → RegisterActivity → VerificationActivity → ProfileActivity

HomeActivity → ProductListActivity → ProductDetailActivity

SettingsActivity with Multiple sub-screens

Each screen transition meant:

What Single Activity Gave Us

Moving to a single activity immediately delivered:

At the time, this felt like cleaning up years of accumulated architectural debt.
For many use cases, this was absolutely the right call:

But there were trade-offs we didn’t anticipate.

Part 2: Where It Started to Break for Us

1. Deep Linking Becomes Confusing

The Problem

Single-activity architecture centralizes entry points. With multiple activities, any activity can be launched independently. With a single activity, everything funnels through MainActivity.
In a fintech app with:

This assumption started to fail.

**What we saw in production \ When users tapped a deep link from a notification while the app was notin memory, the navigation stack wasn’t fully initialized.

kotlin

// App process is dead
// MainActivity is created
// Navigation graph builds
// Fragment back stack depends on assumptions that haven't been met

The Result:


With multiple activities, each activity was self-contained. A DeepLinkHandlerActivity could exist independently and route users appropriately.

2. Memory Pressure and Task Affinity Lose Flexibility

The Problem

In a multiple activity architecture, you could separate heavyweight features into distinct activities with different task affinity and launch modes:

<activity 
          android:name=".features.videocall.VideoCallActivity" 
          android:taskAffinity=".videocall" 
          android:launchMode="singleTask" />

This allowed:

What broke

In a Single activity world:

The solution?

We reintroduced a separate VideoCallActivity.

Outcome: Suddenly, memory profiling improved, and the feature became more stable.

3. Launch Modes and Back Stack Control Become Difficult

The Problem:Some features need non-standard back-stack behavior:
Authentication flow: Should create a new back stack, not integrate into the existing one
onboarding wizard: Should be clearable entirely, not stored in history
Feature modules: Should be launchable independently without requiring going through the main app flow

A single activity makes this hard. You end up either:


With multiple activities, intent flags, and launch modes made intent explicit:

<activity 
          android:name=".auth.LoginActivity" 
          android:launchMode="singleTask" 
          android:taskAffinity=".auth" />

This is explicit, maintainable, and respects Android's design principles.

4. Modular Architecture and Feature Isolation Become Awkward

The Problem: Modern Android development embraces feature modules.

With single-activity, every feature had to plug into the main navigation graph:


Feature Module (Payment) → Knows about Main Navigation Graph 
Feature Module (Chat) → Knows about Main Navigation Graph 
Main App → Coordinates everything

The navigation graph becomes a dependency bottleneck.

With multiple activities:


Feature Module (Payment) → Exports PaymentActivity
Feature Module (Chat) → Exports 
ChatActivity Main App → Launches via Intent

launches them via IntentFeature modules that remain loosely coupled, testable, and autonomous.

5. Rotation, Configuration Changes, and Screen-Specific Concerns

The Problem

In a single activity:

Some screens needed custom handling:

In single-activity, your one activity becomes a god object managing the rotation behavior for dozens of fragments. In multiple activities, VideoPlayerActivity can handle its rotation, and DrawingActivity can handle its rotation independently.

6. Process Death and Restoration Becomes Complicated

The Problem: Android can kill your app process when memory is low. When the user returns, the OS should restore your app's state.


With multiple activities, it's straightforward:

With single-activity:

Isolated activities reduced the blast radius significantly.

Part 3: What We Ended Up Doing Instead

After 3+ years of single activity production experience and 2+ years of refactoring back to a hybrid approach, here's what we now implement:

The Rule: Multiple Activities for Major Feature Boundaries

We use separate activities when a feature:

Otherwise, we use fragments within a main activity.


Our Architecture Today:


MainActivity
├── HomeFragment
├── ProductListFragment
├── ProductDetailFragment
└── SettingsFragment

AuthActivity
├── LoginFragment
├── RegisterFragment
└── ForgotPasswordFragment

VideoCallActivity
└── Full-screen video UI

PaymentActivity
├── PaymentMethodFragment
├── ConfirmationFragment
└── ReceiptFragment

Benefits We've Measured:

Part 4: Modern Android Frameworks Change the Calculus

Jetpack Compose Is Different

Single activity architecture was optimized for XML layout-based Android development. With Jetpack Compose, the rules change.


@Composable
 fun MainApp() {
     NavHost(navController, startDestination = "home") {
         composable("home") { HomeScreen() }
         composable("products") { ProductListScreen() }
         composable("payment") { PaymentScreen() }
     }
 } 

Compose:

Predictive Back Gesture and Gesture Navigation

Modern Android (15+) emphasizes gesture-based navigation. This actually favors single-activity because gestures operate at the activity level. Multiple activities create gesture inconsistencies across features.
We're watching this space closely.

Part 5: Choosing the Right Architecture for Your Project

Use this framework to decide:

Use Single Activity When:


Use Hybrid (Multiple Activities) When:


My Recommendation for Enterprise:

Use a hybrid architecture with Jetpack Compose:

Modular, testable, scalable, and maintain Google's best approaches/practices

Part 6: Real-World Lessons from Production

**Lesson 1: Architectural Decisions Are Reversible (But Expensive):**Refactoring a production app from single to multiple activities took us 4 months and 150+ pull requests. If we had to do a hybrid decision upfront, we'd have saved 6 months of engineering time across the project lifecycle.

Takeaway: Don't blindly follow industry consensus. Understand the trade-offs for YOUR project.

Lesson 2: Fragments Aren't Going Away: You’ll often see claims that single-activity with fragments is outdated. That framing misses the point. Fragments remain a first-class tool for building reusable UI on Android. The debate isn’t about fragments themselves, but about whether every fragment should be hosted by one activity.

**Lesson 3: Profile Before Optimizing:**We spent weeks speculating about memory issues. Profiling showed the video calling feature was the actual culprit. Move one feature to a separate activity, memory restored.

Takeaway: Use Android Profiler early and often. Let data guide architecture.

Lesson 4: Testing Improves With Multiple Activities: Single-activity created test complexity because navigation graph configuration became test boilerplate. Multiple activities simplified testing because each activity tests independently.

Conclusion: The Right Tool for the Job

I've spent 12 years watching Android architecture evolve. Here's what I'm confident about:
Google’s recommendations were well-suited in 2018, when apps were less complex, and Jetpack Compose didn’t yet exist.

Single activity is still correct for many projects (startups, simple utilities, Compose-first apps)

Hybrid is more practical for enterprise apps that have grown organically with various feature needs

There is no one correct answer - only trade-offs

Architecture should serve your product and your team, not ideology.

Single-activity architecture isn’t wrong — it’s just incomplete as a universal rule.

The best Android architecture is the one that helps your team ship reliably, recover gracefully, and evolve without friction.

References & Further Reading

Android Developers Guide to Architecture - https://developer.android.com/topic/architecture
Jetpack Navigation Component - https://developer.android.com/guide/navigation
Modern Activity Lifecycle - https://developer.android.com/guide/components/activities
Jetpack Compose Navigation - https://developer.android.com/jetpack/compose/navigation
Deep Linking Best Practices - https://developer.android.com/training/app-links
Modular Architecture with Feature Modules - https://developer.android.com/training/modular-architecture